用一段代码和结果来证明上面的理论
Appconfig.java
@ComponentScan(“com.enjoy.beanDefinition”)
@Configuration
public class Appconfig {
}
X.java
@Component
public class X {
public X(){
System.out.println(“X Constructor”);
}
}
Y.java
public class Y {
}
Test.java
public class Test{
public static void main(String[] args) {
AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext();
ac.register(Appconfig.class);
ac.refresh();
}
}
④当spring把类所对应的beanDefintion对象存到map之后,spring会调用程序员提供的bean工厂后置处理器。什么叫bean工厂后置处理器?在spring的代码级别是用一个接口来表示BeanFactoryPostProcessor,只要实现这个接口便是一个bean工厂后置处理器了,BeanFactoryPostProcessor的详细源码解析后面文章再来分析,这里先说一下他的基本作用。BeanFactoryPostProcessor接口在spring内部也有实现,比如第①步当中完成扫描功能的类ConfigurationClassPostProcessor
便是一个spring自己实现的bean工厂后置处理器,这个类笔者认为是阅读spring源码当中最重要
的类,没有之一;他完成的功能太多了,以后我们一一分析,先看一下这个类的类结构图。
ConfigurationClassPostProcessor
实现了很多接口,和本文有关的只需关注两个接口BeanDefinitionRegistryPostProcessor
和BeanFactoryPostProcessor
;但是由于BeanDefinitionRegistryPostProcessor
是继承了BeanFactoryPostProcessor
所以读者也可以理解这是一个接口,但是笔者更加建议你理解成两个接口比较合适,因为spring完成上述①②③步的功能就是调用BeanDefinitionRegistryPostProcessor
的postProcessBeanDefinitionRegistry
方法完成的,到了第④步的时候spring是执行BeanFactoryPostProcessor
的postProcessBeanFactory
方法;这里可能说的有点绕,大概意思spring完成①②③的功能是调用ConfigurationClassPostProcessor
的BeanDefinitionRegistryPostProcessor
的postProcessBeanDefinitionRegistry
方法,到了第④步spring首先会调用ConfigurationClassPostProcessor
的BeanFactoryPostProcessor
的postProcessBeanFactory
的方法,然后在调用程序员提供的BeanFactoryPostProcessor
的postProcessBeanFactory
方法,所以上图当中第④步我画的是红色虚线,因为第④步可能没有(如果程序员没有提供自己的BeanFactoryPostProcessor
;当然这里一定得说明,即使程序员没有提供自己扩展的BeanFactoryPostProcessor
,spring也会执行内置的BeanFactoryPostProcessor
也就是ConfigurationClassPostProcessor
,所以上图画的并不标准,少了一步;即spring执行内置的BeanFactoryPostProcessor
;
重点:我们用自己的话总结一下BeanFactoryPostProcessor
的执行时机(不管内置的还是程序员提供)————Ⅰ:如果是直接实现BeanFactoryPostProcessor
的类是在spring完成扫描类之后(所谓的扫描包括把类变成beanDefinition然后put到map之中),在实例化bean(第⑤步)之前执行;Ⅱ如果是实现BeanDefinitionRegistryPostProcessor
接口的类;诚然这种也叫bean工厂后置处理器他的执行时机是在执行直接实现BeanFactoryPostProcessor
的类之前,和扫描(上面①②③步)是同期执行;假设你的程序扩展一个功能,需要在这个时期做某个功能则可以实现这个接口;但是笔者至今没有遇到这样的需求,如果以后遇到或者看到再来补上;(说明一下当笔者发表这篇博客有一个读者联系笔者说他看到了一个主流框架就是扩展了BeanDefinitionRegistryPostProcessor
类,瞬间笔者如久旱遇甘霖,光棍遇寡妇;遂立马请教;那位读者说mybatis的最新代码里面便是扩展这个类来实现的,笔者记得以前mybatis是扩展没有用到这个接口,后来笔者看了一下最新的mybatis源码确实如那位读者所言,在下一篇笔者分析主流框架如何扩展spring的时候更新)
这里再次啰嗦一下,这一段比较枯燥和晦涩,但是非常重要,如果想做到精读spring源码这一段尤为重要,建议读者多看多理解;
那么第④步当中提到的执行程序员提供的BeanFactoryPostProcessor
到底有什么意义呢?程序员提供BeanFactoryPostProcessor
的场景在哪里?有哪些主流框架这么干过呢?
首先回答第一个问题,意义在哪里?可以看一下这个接口的方法签名
void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory)
throws BeansException;
其实讨论这个方法的意义就是讨论BeanFactoryPostProcessor
的作用或者说意义,参考这个方法的一句javadoc
Modify the application context’s internal bean factory after its standard initialization
在应用程序上下文的标准初始化之后修改它的内部bean工厂
再结合这个方法的执行时机和这段javadoc我们可以理解bean工厂的后置处理器(这里只讨论直接实现BeanFactoryPostProcessor
的后置处理器,不包括实现BeanDefinitionRegistryPostProcessor
的后置处理器)其实是spring提供的一个扩展点(spring提供很多扩展点,学习spring源码的一个非常重要的原因就是要学会这些扩展点,以便对spring做二次开发或者写出优雅的插件),可以让程序员干预bean工厂的初始化过
程(重点会考);这句话最重要的几个字是初始化过程,注意不是实例化过程 ;初始化和实例化有很大的区别的,特别是在读spring源码的时候一定要注意这两个名词;翻开spring源码你会发现整个容器初始化过程就是spring各种后置处理器调用过程;而各种后置处理器当中大体分为两种;一种关于实例化的后置处理器一种是关于初始化的后置处理
《一线大厂Java面试题解析+后端开发学习笔记+最新架构讲解视频+实战项目源码讲义》
【docs.qq.com/doc/DSmxTbFJ1cmN1R2dB】 完整内容开源分享
器,这里不是笔者臆想出来的,如果读者熟悉spring的后置处理器体系就可以从spring的后置处理器命名看出来spring对初始化和实例化是有非常大的区分的。
说白了就是——beanFactory怎么new出来的(实例化)BeanFactoryPostProcessor
是干预不了的,但是beanFactory new出来之后各种属性的填充或者修改(初始化)是可以通过BeanFactoryPostProcessor
来干预;可以看到BeanFactoryPostProcessor
里唯一的方法postProcessBeanFactory
中唯一的参数就是一个标准的beanFactory对象——ConfigurableListableBeanFactory;既然spring在调用postProcessBeanFactory
方法的时候把已经实例化好的beanFactory对象传过来了,那么自然而然我们可以对这个beanFactory肆意妄为了;
虽然肆意妄为听起来很酷,实则很多人会很迷茫;就相当于现在送给了你一辆奥迪A6(笔者的dream car!重点会考)告诉你可以对这辆车肆意妄为,可你如果只是会按按喇叭,那就对不起赠送者的一番美意了;其实你根本不知道可以在午夜开车这辆车去长沙的解放西路转一圈,继而会收货很多意外的“爱情”;笔者举这个例子就是想说当你拿到beanFactory对象的时候不能只会sout,那不叫肆意妄为;我们可以干很多事情,但是你必须要了解beanFactory的特性或者beanFactory的各种api,但是beanFactory这个对象太复杂了,这里不适合展开讨论,与本文相关的只要知道上述我们讲到的那个beanDefintionMap(存储beanDefintion的集合)就定义在beanFactory当中;而且他也提供额api供程序员来操作这个map,比如可以修改这个map当中的beanDefinition对象,也可以添加一个beanDefinition对象到这个map当中;看一段代码
@Component
public class TestBeanFactoryPostPorcessor implements BeanFactoryPostProcessor {
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
//转换为子类,因为父类没有添加beanDefintion对象的api
DefaultListableBeanFactory defaultbf =
(DefaultListableBeanFactory) beanFactory;
//new一个Y的beanDefinition对象,方便测试动态添加
GenericBeanDefinition y= new GenericBeanDefinition();
y.setBeanClass(Y.class);
//添加一个beanDefinition对象,原本这个Y没有被spring扫描到
defaultbf.registerBeanDefinition(“y”, y);
//得到一个已经被扫描出来的beanDefintion对象x
//因为X本来就被扫描出来了,所以是直接从map中获取
BeanDefinition x = defaultbf.getBeanDefinition(“x”);
//修改这个X的beanDefintion对象的class为Z
//原本这个x代表的class为X.class;现在为Z.class
x.setBeanClassName(“com.enjoy.beanDefinition.Z”);
}
}