Spring 中 bean 工厂后置处理器也就是 BeanFactoryPostProcessor 接口,是用来干什么的呢?我们都知道一个好的框架必备的特性至少得有开闭原则,可扩展性。
在前面的文章里 SpringIOC 源码阅读—BeanDefinitionDocumentReader 我们了解到 Spring 对 bean 定义的载入有很多种方式,读取的过程是可插拔的,不论何种形式,spring 的 IOC 容器只要获得了 bean 定义信息,都可以正常工作。而我们熟知的配置读取方式就是 XML 文件,如果你希望,可以自己定制配置信息的读取过程,这就是 Spring 的特性体现之一。
同样
也是 Spring 可扩展性的一个体现,我们读一下这个接口的源码
- BeanFactoryPostProcessor
- public interface BeanFactoryPostProcessor {
- /**
- * Modify the application context's internal bean factory after its standard
- * initialization. All bean definitions will have been loaded, but no beans
- * will have been instantiated yet. This allows for overriding or adding
- * properties even to eager-initializing beans.
- * @param beanFactory the bean factory used by the application context
- * @throws org.springframework.beans.BeansException in case of errors
- */
- void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException;
- }
注释的意思是允许我们在工厂里所有的 bean 被加载进来后但是还没初始化前,对所有 bean 的属性进行修改也可以 add 属性值。
下面通过实例看下效果
beans.xml
- <?xml version="1.0" encoding="UTF-8"?>
- <beans xmlns="http://www.springframework.org/schema/beans"
- xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">
- <!-- 普通的bean -->
- <bean id="user" init-method="init" class="xz.quartz.analysis.User"></bean>
- <!-- BeanFactroy后置处理器 -->
- <bean id="beanfactorypostpro" class="xz.quartz.analysis.beanfactorypostpro"></bean>
- </beans>
我们定义一个普通 bean 和一个 BeanFactroy 后置处理器
User 类
- package xz.quartz.analysis;
- public class User {
- String name;
- String age;
- public User() {
- System.out.println("construtor");
- System.out.println("name:" + name + ",age:" + age);
- }
- public void go() {
- System.out.println("age:" + age);
- }
- public String getName() {
- return name;
- }
- public void setName(String name) {
- this.name = name;
- }
- public String getAge() {
- return age;
- }
- public void setAge(String age) {
- this.age = age;
- }
- }
BeanFactroy 后置处理器类
在上面 BeanFactoryPostProcessor 的实现类里通过我写的注释可以看到这个工厂后置器获取到所有的 beanName,并且可以对特定的 bean 或者全部 bean 进行操作,这也就是后置器的核心所在之处。
- package xz.quartz.analysis;
- import org.springframework.beans.BeansException;
- import org.springframework.beans.MutablePropertyValues;
- import org.springframework.beans.factory.config.BeanDefinition;
- import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
- import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
- public class beanfactorypostpro implements BeanFactoryPostProcessor {@Override public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
- System.out.println("******调用BeanFactoryPostProcessor开始");
- //获取到Spring中所有的beanName
- String[] beanStr = beanFactory.getBeanDefinitionNames();
- //循环bean做出自定义的操作
- for (String beanName: beanStr) {
- System.out.println("bean name:" + beanName);
- if ("user".equals(beanName)) {
- BeanDefinition beanDefinition = beanFactory.getBeanDefinition(beanName);
- System.out.println("修改user的age值");
- beanDefinition.getPropertyValues().add("age", "20");
- }
- }
- System.out.println("******调用BeanFactoryPostProcessor结束");
- }
- }
main 方法
- public static void main(String[] args) {
- ApplicationContext applicationContext = new ClassPathXmlApplicationContext("classpath:beans.xml");
- System.out.println("获取到User实例 ");
- ((User)applicationContext.getBean("user")).go();
- }
主函数中第一行初始化的时候,读取 beans.xml 时,会获取实现了 BeanFactoryPostProcessor 接口的 bean,然后把它作为后置处理器类来处理。
然后我们通过调用 user 的 go 方法,输出 age 的值来看下
- ******调用BeanFactoryPostProcessor开始
- bean name:user
- 修改user的age值
- bean name:beanfactorypostpro
- ******调用BeanFactoryPostProcessor结束
- construtor
- name:null,age:null
- 获取到User实例
- age:20
我们在 BeanFactroy 后置处理器类里给 user 的 age 属性成功赋值成 20,大家通过程序实例可以看到后置处理器的作用和用法了。
在这里提出两个疑问1. 后置处理器和 bean 指定的 init-method 还有构造方法的顺序是谁先谁后呢?
2. 这三个方法同时对属性赋值,最终会是哪个起作用呢?
对上面的两个问题,我们改造下代码,先把构造方法加上赋值过程
User 类
- package xz.quartz.analysis;
- public class User {
- String name;
- String age;
- void init() {
- System.out.println("init");
- }
- public User() {
- System.out.println("construtor");
- name = "zx-construtor";
- age = "zx-construtor";
- System.out.println("name:" + name + ",age:" + age);
- }
- public void go() {
- System.out.println("最终age的值:" + age);
- }
- public String getName() {
- return name;
- }
- public void setName(String name) {
- this.name = name;
- }
- public String getAge() {
- return age;
- }
- public void setAge(String age) {
- this.age = age;
- }
- }
输出结果:
- ******调用BeanFactoryPostProcessor开始
- bean name:user
- 修改user的age值
- bean name:beanfactorypostpro
- ******调用BeanFactoryPostProcessor结束
- construtor
- name:zx-construtor,age:zx-construtor
- init
- name:zx-construtor,age:20
- 获取到User实例
- 最终age的值:20
可以看到程序先执行后置器将值改为
,然后执行的构造方法,改为 zx-construtor,但是最终 age 的值为
- 20
,到这里疑问就来了,为什么后执行的赋值没起作用呢?这个我后面解读源码的时候再聊。
- 20
我们继续把 init-method 方法加上
- package xz.quartz.analysis;
- public class User {
- String name;
- String age;
- void init() {
- System.out.println("init");
- name = "zx-init";
- age = "zx-init";
- System.out.println("name:" + name + ",age:" + age);
- }
- public User() {
- System.out.println("construtor");
- name = "zx-construtor";
- age = "zx-construtor";
- System.out.println("name:" + name + ",age:" + age);
- }
- public void go() {
- System.out.println("最终age的值:" + age);
- }
- public String getName() {
- return name;
- }
- public void setName(String name) {
- this.name = name;
- }
- public String getAge() {
- return age;
- }
- public void setAge(String age) {
- this.age = age;
- }
- }
看输出结果
- ******调用BeanFactoryPostProcessor开始
- bean name:user
- 修改user的age值
- bean name:beanfactorypostpro
- ******调用BeanFactoryPostProcessor结束
- construtor
- name:zx-construtor,age:zx-construtor
- init
- name:zx-init,age:zx-init
- 获取到User实例
- 最终age的值:zx-init
通过上面两个例子我们可以知道这三个方法的执行顺序
bean 工厂后置处理器—> 构造方法—>init-method。
而赋值结果的疑问后续通过源码来解释吧!
来源: http://www.jianshu.com/p/b45efc018bcc