有时我们希望在Spring IoC容器中注册自己的插件,在构造期间处理Bean实例。
Bean后处理器允许在初始化回调方法前后进行附加的Bean处理。Bean后处理器的主要特性是逐个处理IoC容器中的所有Bean实例,而不是单个Bean实例。
Bean后处理器的基本要求是实现BeanPostProcessor接口,我们可以实现postProcessAfterInitialization(Object bean, String beanName)和postProcessBeforeInitialization(Object bean, String beanName)方法,在初始化回调方法前后处理所有的Bean。Spring在初始化回调方法前后将Bean实例传给这两个方法,步骤如下:
(1)构造程序或者工厂方法创建Bean实例
(2)为bean属性设置值和Bean引用
(3)调用感知接口中定义的设值方法
(4)将Bean实例传递给每个Bean后处理器中的postProcessBeforeInitialization方法
(5)调用初始化回调方法
(6)将Bean实例传递给每个Bean后处理器中的postProcessAfterInitialization方法
(7)Bean可以使用
(8)容器关闭,调用析构回调方法
使用Bean工厂为IoC容器时,Bean后处理器只能编程注册,更准确是通过addBeanPostProcessor()方法注册。但是,如果使用应用上下文,注册很简单,只要在Bean配置文件中声明一个处理器实例即可。
一、Bean代码
public class EnglishCourse implements Course {
private String name;
private int lessons;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getLessons() {
return lessons;
}
public void setLessons(int lessons) {
this.lessons = lessons;
}
}
二、客户化Bean后处理器代码
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
public class CustomBeanProcess implements BeanPostProcessor {
@Override
public Object postProcessAfterInitialization(Object bean, String beanName)
throws BeansException {
System.out.println("初始化之后执行bean后处理器");
if(bean instanceof EnglishCourse){
EnglishCourse ec = (EnglishCourse)bean;
ec.setName("英语教材");
ec.setLessons(45);
}
return bean;
}
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName)
throws BeansException {
System.out.println("初始化之前执行bean后处理器");
return bean;
}
}
三、Bean配置文件
<bean class="com.apress.springrecipes.process.CustomBeanProcess"/>
<bean id="ec" class="com.apress.springrecipes.process.EnglishCourse"/>
如果我们在init-method属性中指定初始化回调方法,或者实现InitializingBean接口,我们的CustomBeanProcess就会很好的工作。
但是,如果EnglishCourse依赖于注解@PostConstruct和@PreDestroy,而且一个CommonAnnotationBeanPostProcessor实例调用初始化方法,那么CustomBeanProcess将不能正常工作。这是因为我们的Bean后处理器的默认优先级低于CommonAnnotationBeanPostProcessor。结果初始化方法将在postProcessBeforeInitialization该方法之前执行。
为了定义Bean后处理器的处理顺序,可以实现它们的Ordered或者PriorityOrdered接口,并在getOrder()方法中返回顺序。这个方法的返回值越低,就代表越高的优先级,PriorityOrdered接口返回的顺序总是优先于Ordered接口的返回值。
因为CommonAnnotationBeanPostProcessor实现了PriorityOrdered接口,所以CustomBeanProcess也必须实现这个接口。