@ghimi
2018-10-14T12:07:09.000000Z
字数 4657
阅读 757
Spring
BeanPostProcessor 是 Spring 中定义的一个接口,其与之前介绍的 InitializingBean 和 DisposableBean 接口类似,也是提供 Spring 进行回调的.Spring 将在初始化 bean 前后对 BeanPostProcessor 实现类进行回调,与 InitializingBean 和 DisposableBean 接口不同的是 BeanPostProcessor 接口将对所有的 bean 都起作用,即所有的 bean 初始化前后都会回调 BeanPostProcessor 实现类,而 InitializingBean 和 DisposableBean 接口是针对单个 bean 的,即只有在对应的 bean 实现了 InitializingBean 或 DispoableBean 接口才会对其进行回调.
BeanPostProcessor 接口的定义如下:
public interface BeanPostProcessor {
Object postProcessBeforeInitialization(Object bean,String beanName)throws BeansException;
Object postProcessAfterInitialization(Object bean,String beanName)throws BeansException;
}
如你所见, BeanPostProcessor 接口中定义了两个方法,其中方法 postProcessorBeforeInitialization() 将在一个 bean 被完全初始化前进行回调,此时对应的 bean 已经实例化了,但是对应的属性注入定还没有进行,即在调用 InitializingBean 的 afterPropertiesSet()方法或 bean 对应的 init-method 之前;而方法 postProcessAfterInitialization() 将在 bean 被完全初始化后进行回调,此时对应的以来注入已经完成,即在调用 InitializingBean 的 afterPropertiesSet() 方法后对应的 init-method 方法之后.
两个方法的参数以及返回值对应的意义都是一样的,其中参数 bean 表示当前状态的 bean ,参数 beanName 表示当前 bean 的名称,而方法对应的返回值即表示需要放入到 bean 容器的 bean ,所以用户如果有需要完全可以在这两个方法中对 bean 进行修改,即封装自己的 bean 进行返回.
以下是 Spring 源码中对 bean 进行初始化的逻辑,从源码中我们可以看到是先通过 applyBeanPostProcessorBeforeInitialization() 方法使用注册的 BeanPostProcessor 的 postProcessBeforeInitialization() 方法依次回调,然后是通过 invokeInitMethods() 方法依次调用当前的 bean 对应的初始化方法,再通过 applyBeanPostProcessorsAfterInitialization 方法使用注册的 BeanPostProcessor 的 postProcessorAfterInitialization() 方法依次进行回调.
protected Object initializeBean(final String beanName,final Object bean,RootBeanDefinition mbd){
if(System.getSecurtiyManager() != null){
AccessController.doPrivileged(new PrivilegedAction<Object>(){
@Oberride
public Object run(){
invokeAwareMethods(beanName,bean);
return null;
}
},getAccessControlContext());
}else {
invokeAwareMethods(beanName,bean);
}
Object wrappedBean = bean;
if(mbd == null || !mbd.isSynthetic()){
wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean,beanName);
}
try{
invokeInitMethods(beanName,wrappedBean,mbd);
}catch(Throwable ex){
throw new BeanCreationException(mbd != null ?mbd.getResourcDescription():beanName,"Invocation of init method failed",ex);
}
if(mbd == null || !mbd.isSynthetic()){
wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean,beanName);
}
return wrappedBean;
}
BeanPostProcessor 的注册是非常简单的,我们只需要把它当做一个普通的 Bean 定义到 Spring 的 bean 容器中, Spring 能够自动检测到它,并将它注册到当前的 bean 容器中. BeanPostProcessor 是容器绑定的,即 BeanPostProcessor 只能对跟它同属于同一个 bean 容器中的 bean 进行回调,即 BeanPostProcessor不能对属于它父容器或子容器的 bean 进行回调.
在 bean 容器中定义了 BeanPostProcessor 之后,Spring 将最先将 BeanPostProcessor 对应的 bean 进行实例化,如果我们制定的 BeanPostPorcessor 的 lazy-initialization="true" 或 default-lazy-initialization="true",Spring 将对其进行忽略,即这些配置对 BeanPostProcessor 不起作用.这也很好理解,因为只有这样之后在实例化其它 bean 的时候将优先初始化 depends-on 属性制定的 bean , 所以当我们的 BeanPostProcessor 通过 depends-on 指定了对其它 bean 的依赖时,其它 bean 是不会被 BeanPostProcessor 实例化,当然这里也包括简介的 depends-on 对应的 bean .
此外 ,在 BeanPostProcessor 实例化后需要直接或间接的进行注入的 bean 也由于实例化时间提前不会被 BeanPostProcessor 回调.还有就是 BeanPostProcessor 之间不会进行回调,即 BeanPostProcessorA 不会在 BeanPostProcessorB 初始化时对其进行回调.
BeanPostProcessor 在Spring 内部也是用的比较多的,尤其是 AOP 代理部分.包括用户需要自己实现 BeanPostProcessor 实现代理功能时也需要注意 BeanPostProcessor 直接或间接关联的 bean 是不会被回调的,即不会被代理成功的.
接下来看一个简单的定制自己的 BeanPostProcessor 的示例,在示例中我们将仅仅简单的实现一个 BeanPostProcessor ,在 postProcessBeforeInitialization() 和 postProcessAfterInitialization() 方法中都是直接返回对应的 bean ,然后在 postProcessBeforeInitialization() 方法中简单的打印一下对应的 bean 名称
public class HelloBeanPostProcessor implements BeanPostProcessor {
public Object postProcessBeforeInitialization(Object bean,String beanName)throws BeansException {
System.out.println("beanName------------" + beanName);
return bean;
}
public Object postProcessAfterInitialization(Object bean,String beanName){
return bean;
}
}
实现了 BeanPostProcessor 之后就可以将其定义到bean 容器中,其定义方式跟普通 bean 的定义方式是一样的.
<bean class="com.app.HelloBeanPostProcessor"/>
在 bean 容器中我们可以同时定义多个 BeanPostProcessor ,这样在实例化一个 bean 后将以此使用每个 BeanPostProcessor 回调一遍,当然,如果某一个 BeanPostProcessor 回调后返回的 bean 为 null ,则不再继续往下回调,将直接返回 null ,这个时候 bean 容器中对应的 beanName 对应的 bean 也是 null.当在一个 bean 容器中同时定义多个 BeanPostProcessor 时,默认将根据 BeanPostProcessor 在 bean 容器中定义的先后顺序对新实例化的 bean 进行回调.还有一种定义的 BEanPostProcessor 回调顺序是将我们自定义的 BeanPostProcessor 实现类同时实现 Ordered 接口,然后 Spring 将根据 Ordered 接口定义的 getOrder() 方法的返回值来决定 BeanPostProcessor 回调的先后顺序,getOrder() 返回值越小的越先进行回调.此外,实现了 Ordered接口的 BeanPostProcessor 总是比没有实现 Ordered 接口的 BeanPostProcessor 先进行回调,为了便于管理,推荐要么都实现 Ordered 接口,要么都不识闲.以下是一个实现了 Ordered接口 ,并把 getOrder( ) 方法的返回值作为一个参数进行配置的示例
public class HelloPostProcessor implements BeanPostProcessor,Ordered {
private int order;
pulic Object postProcessBeforeIntialization(Object bean,String beanName) throws BeanExcepiton{
System.out.println("beanName----------"+beanName);
return bean;
}
public void setOrder(int order){
this.order = order;
}
public int getOrder(){
return order;
}
}
之后就可以在配置的时候通过参数 order 来指定我们的 getOrder() 方法的返回值.
<bean class="com.app.HelloBeanPostProcessor" p:order="3"/>