Spring IOC官方文档学习笔记(八)之容器扩展点
1.通过BeanPostProcessor来自定义bean
(1) BeanPostProcessor用于在容器完成了对bean的实例化,配置及初始化后来实现一些自定义逻辑,它是用于操纵由容器创建的每个bean实例的,即在容器实例化了一个bean后以及该bean的初始化回调(如InitializingBean.afterPropertiesSet()等)被执行之前,会将这个bean交由BeanPostProcessor来进行处理。通过BeanPostProcessor,我们可以对bean实例进行任何操作,包括忽略掉初始化回调等,BeanPostProcessor通常用来检查回调接口,或用来生成某个bean的代理对象,因此一些Spring AOP的基础类就被实现为BeanPostProcessor实例,以提供代理对象,如下是简单使用BeanPostProcessor的一个例子
//让ExampleA实现3个初始化回调
public class ExampleA implements InitializingBean {
private String name;
public ExampleA() {
System.out.println("ExampleA的构造方法被调用");
System.out.println("----------------------------------------");
}
//这个方法只用于IOC的属性注入
public void setName(String name) {
System.out.println("IOC对ExampleA的name属性进行注入,值为:" + name);
System.out.println("----------------------------------------");
this.name = name;
}
//这个方法用于我们自己手动注入
public void setNameInOtherWay(String name) {
this.name = name;
}
public String getName() {
return name;
}
@Override
public String toString() {
return "ExampleA{" +
"name="" + name + """ +
"}";
}
@PostConstruct
public void postConstruct() {
System.out.println("正在执行初始化回调PostConstruct,此时的ExampleA为:" + this);
this.setNameInOtherWay("zzz2");
System.out.println("执行完毕,此时的ExampleA为:" + this);
System.out.println("----------------------------------------");
}
@Override
public void afterPropertiesSet() throws Exception {
System.out.println("正在执行初始化回调InitializingBean.afterPropertiesSet,此时的ExampleA为:" + this);
this.setNameInOtherWay("zzz3");
System.out.println("执行完毕,此时的ExampleA为:" + this);
System.out.println("----------------------------------------");
}
public void init() {
System.out.println("正在执行初始化回调init-method,此时的ExampleA为:" + this);
this.setNameInOtherWay("zzz4");
System.out.println("执行完毕,此时的ExampleA为:" + this);
System.out.println("----------------------------------------");
}
}
//实现BeanPostProcessor,自定义后置处理器来操纵bean实例(注意:需要把我们的自定义处理器注入到容器中),它主要提供了2个方法
public class Processor implements BeanPostProcessor {
/**
* 该方法作用于bean实例创建配置好后,初始化回调执行前,来自定义一些逻辑
* @param bean 实例化并配置好后的bean
* @param beanName bean的名称
* @return 自定义操作完成后的bean
* @throws BeansException
*/
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
System.out.println("正在执行postProcessBeforeInitialization,此时的ExampleA为:" + bean);
((ExampleA) bean).setNameInOtherWay("zzz1");
System.out.println("执行完毕,此时的ExampleA为:" + bean);
System.out.println("----------------------------------------");
return bean;
}
/**
* 该方法作用于初始化回调执行后
*/
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
System.out.println("正在执行postProcessAfterInitialization,此时的ExampleA为:" + bean);
((ExampleA) bean).setNameInOtherWay("zzz5");
System.out.println("执行完毕,此时的ExampleA为:" + bean);
System.out.println("----------------------------------------");
return bean;
}
}
<!-- xml配置文件 -->
<beans ....>
<!-- 开启注解扫描,否则PostConstruct注解不生效 -->
<context:annotation-config></context:annotation-config>
<bean id="exampleA" class="cn.example.spring.boke.ExampleA" init-method="init">
<property name="name" value="zzz"></property>
</bean>
<!-- 注意仅仅实现接口是不行的,我们必须把自定义后置处理器注册成bean,它才会生效 -->
<bean id="processor" class="cn.example.spring.boke.Processor"></bean>
</beans>
//启动容器后,打印结果为
ExampleA的构造方法被调用
----------------------------------------
IOC对ExampleA的name属性进行注入,值为:zzz
----------------------------------------
正在执行postProcessBeforeInitialization,此时的ExampleA为:ExampleA{name="zzz"}
执行完毕,此时的ExampleA为:ExampleA{name="zzz1"}
----------------------------------------
正在执行初始化回调PostConstruct,此时的ExampleA为:ExampleA{name="zzz1"}
执行完毕,此时的ExampleA为:ExampleA{name="zzz2"}
----------------------------------------
正在执行初始化回调InitializingBean.afterPropertiesSet,此时的ExampleA为:ExampleA{name="zzz2"}
执行完毕,此时的ExampleA为:ExampleA{name="zzz3"}
----------------------------------------
正在执行初始化回调init-method,此时的ExampleA为:ExampleA{name="zzz3"}
执行完毕,此时的ExampleA为:ExampleA{name="zzz4"}
----------------------------------------
正在执行postProcessAfterInitialization,此时的ExampleA为:ExampleA{name="zzz4"}
执行完毕,此时的ExampleA为:ExampleA{name="zzz5"}
----------------------------------------
综上可见,添加了BeanPostProcessor后,bean的初始化流程为:执行bean的构造函数 -> IOC进行属性注入 -> BeanPostProcessor.postProcessBeforeInitialization -> 三大初始化回调 -> BeanPostProcessor.postProcessAfterInitialization
(2) 我们可以向容器中注入多个自定义BeanPostProcessor,并通过实现Ordered接口来控制这些BeanPostProcessor的执行顺序,如下所示
public class ExampleA { }
//让该自定义后置处理器实现Ordered接口,指定它在所有自定义后置处理器中的执行顺序
public class Processor0 implements BeanPostProcessor, Ordered {
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
System.out.println("Order值为0的postProcessBeforeInitialization执行...");
return bean;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
System.out.println("Order值为0的postProcessAfterInitialization执行...");
return bean;
}
@Override
public int getOrder() {
return 0;
}
}
public class Processor1 implements BeanPostProcessor, Ordered {
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
System.out.println("Order值为1的postProcessBeforeInitialization执行...");
return bean;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
System.out.println("Order值为1的postProcessAfterInitialization执行...");
return bean;
}
@Override
public int getOrder() {
return 1;
}
}
<!-- xml配置文件 -->
<beans ....>
<bean id="exampleA" class="cn.example.spring.boke.ExampleA"></bean>
<bean id="processor0" class="cn.example.spring.boke.Processor0"></bean>
<bean id="processor1" class="cn.example.spring.boke.Processor1"></bean>
</beans>
//启动容器,输出如下
Order值为0的postProcessBeforeInitialization执行...
Order值为1的postProcessBeforeInitialization执行...
Order值为0的postProcessAfterInitialization执行...
Order值为1的postProcessAfterInitialization执行...
由上可见,getOrder返回值越小,自定义的后置处理器就越先执行
(3) 在一个容器中注入了一个BeanPostProcessor,那么该BeanPostProcessor仅对该容器中的bean进行后置处理,例如,即父容器中的BeanPostProcessor不会作用于子容器中的bean
(4) BeanPostProcessor作用于bean实例化并配置好了之后,换句话说,在BeanPostProcessor起作用时,bean实例已经存在了,因此,如果我们想要修改bean的配置元数据(即BeanDefinition,此时的bean还未被创建),则需要实现BeanFactoryPostProcessor接口,它与BeanPostProcessor类似,只不过作用时机不同
未完待续…