BeanFactoryPostProcessor的调用时机
BeanFactoryPostProcessor其实就是BeanFactory(创建bean的工厂)的后置处理器。说起这个,你脑海中是不是泛起了回忆,是不是想起了有一个与BeanFactoryPostProcessor的名字极其相似的玩意,它就是BeanPostProcessor。那什么是BeanPostProcessor呢?我们之前早就说过了,它就是bean的后置处理器,并且是在bean创建对象初始化前后进行拦截工作的。
现在我们要讲解的是BeanFactoryPostProcessor,上面也说过了,它是BeanFactory(创建bean的工厂)的后置处理器。接下来,我们就要搞清楚它的内部原理了,想要搞清楚其内部原理,我们需要从它是什么时候工作这一点开始入手研究,也即搞清楚它的调用时机是什么。
我们点进去BeanFactoryPostProcessor的源码里面去看一看,发现它是一个接口,如下图所示。
仔细看一下其内部postProcessBeanFactory方法上的描述,这很重要,因为从这段描述中我们就可以知道BeanFactoryPostProcessor的调用时机。描述中说,我们可以在IOC容器里面的BeanFactory的标准初始化完成之后,修改IOC容器里面的这个BeanFactory。
也就是说,BeanFactoryPostProcessor的调用时机是在BeanFactory标准初始化之后,这样一来,我们就可以来定制和修改BeanFactory里面的一些内容了。那什么叫标准初始化呢?接着看描述,它说的是所有的bean定义已经被加载了,但是还没有bean被初始化。
说人话,就是BeanFactoryPostProcessor的调用时机是在BeanFactory标准初始化之后,这样一来,我们就可以来定制和修改BeanFactory里面的一些内容了,此时,所有的bean定义已经保存加载到BeanFactory中了,但是bean的实例还未创建。
案例实践
接下来,我们来编写一个案例来验证一下以上说的内容。
首先,我们来编写一个我们自己的BeanFactoryPostProcessor,例如MyBeanFactoryPostProcessor。要编写这样一个bean工厂的后置处理器,它得需要实现我们上面说的BeanFactoryPostProcessor接口,并且还得添加一个实现方法。由于BeanFactoryPostProcessor接口里面只声明了一个方法,即postProcessBeanFactory,所以咱们自己编写的MyBeanFactoryPostProcessor类中只需要实现其即可。
package com.baidu.bean;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.stereotype.Component;
import java.util.Arrays;
@Component
public class MainBeanFactoryPostProcessor implements 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 BeansException in case of errors
*/
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
System.out.println("MyBeanFactoryPostProcessor...postProcessBeanFactory..."); // 这个时候我们所有的bean还没被创建
// 但是我们可以看一下通过Spring给我们传过来的这个beanFactory,我们能拿到什么
int count = beanFactory.getBeanDefinitionCount(); // 我们能拿到有几个bean定义
String[] names = beanFactory.getBeanDefinitionNames(); // 除此之外,我们还能拿到每一个bean定义的名字
System.out.println("当前BeanFactory中有" + count + "个Bean");
System.out.println(Arrays.asList(names));
}
}
注意,我们自己编写的MyBeanFactoryPostProcessor类要想让Spring知道,并且还要能被使用起来,那么它一定就得被加在容器中,为此,我们可以在其上标注一个@Component注解。
然后,创建一个配置类,例如ExtConfig,记得还要在该配置类上使用@ComponentScan注解来配置包扫描哟!
当然了,我们也可以使用@Bean注解向容器中注入咱自己写的组件,例如,在这里,我们可以向容器中注入一个Blue组件。
package com.baidu.config;
import com.baidu.bean.Blue;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
@ComponentScan("com.baidu.bean")
@Configuration
public class ExtFactoryPostConfig {
@Bean
public Blue blue(){
return new Blue();
}
}
上面这个Blue组件其实就是一个非常普通的组件,代码如下所示:
package com.baidu.bean;
public class Blue {
public Blue() {
System.out.println("Blue-->无参的构造方法");
}
public void init(){
System.out.println("Blue...init.....");
}
public void destory(){
System.out.println("Blue...destory....");
}
}
可以看到,在创建Blue对象的时候,无参构造器会有相应打印。
接着,编写一个单元测试类,例如IOCTest_Ext,来进行测试。
@Test
public void test01(){
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(ExtFactoryPostConfig.class);
//关闭容器
context.close();
}
测试啥呢?其实就是来验证一下BeanFactoryPostProcessor的调用时机。说得更具体一点就是,就是看一下咱们自己编写的BeanFactoryPostProcessor究竟是不是在所有的bean定义已经被加载,但是还未创建对象的时候工作?
那咱们接下来就来一探究竟。运行IOCTest_Ext类中的test01方法,可以看到Eclipse控制台打印出了如下内容。
哎呀!咱们自己编写的BeanFactoryPostProcessor在Blue类的无参构造器创建Blue对象之前就已经工作了。细心一点看的话,从bean的定义信息中还能看到Blue组件注册到容器中的名字,只是此刻还没创建对象,如下图所示。
说明BeanFactoryPostProcessor是在所有的bean定义信息都被加载之后才调用的。
https://liayun.blog.csdn.net/article/details/113103870