18-Spring高级容器初始化:BeanFactoryPostProcessor如何执行
2023-06-18 18:48:54    哔哩哔哩

开篇

上一节,我们了解了空实现方法postProcessBeanFactory的作用以及什么是BeanFactoryPostProcessor,同时也自定义实现了它们,体验了下在实际开发过程中一般是如何使用它们的。

这一节,我们的目标就是要搞清楚在ApplicationContext初始化时,所有的工厂后处理器BeanFactoryPostProcessors中的方法是如何执行的,主要分为以下几个部分:

1.首先来看下Spring是如何处理参数传进来的BeanFactoryPostProcessor接口实现类


(资料图)

2.然后再看下Spring容器中,实现了接口BeanDefinitionRegistryPostProcessor的BeanFactoryPostProcessor接口实现类是如何处理的

3.最后再来看下Spring容器中,仅仅只是实现了BeanFactoryPostProcessor接口的实现类是如何处理的

初探方法invokeBeanFactoryPostProcessors

我们回到上节课分析的位置,继续来看下:

可以看到,首先会通过方法getBeanFactoryPostProcessors获取参数中的工厂后处理器BeanFactoryPostProcessor,然后调用方法invokeBeanFactoryPostProcessors执行工厂后处理器中的方法。

我们跟进到方法invokeBeanFactoryPostProcessors中看下:

可以看到,一眼看过去方法invokeBeanFactoryPostProcessors中的逻辑实在是太复杂了。

但是,我们既然是研究Spring的源码,还是很有必要来分析下的,所以,接下来大家务必要耐下心来,为了方便截图,我们将这个方法中的代码分为多个片段逐步来分析。

简单观察了一下方法invokeBeanFactoryPostProcessors之后发现,其实是因为方法里面充斥着大量重复的代码,我们只要把前面一小部分的代码理解透了之后,后面的逻辑梳理起来也就很简单了。

话不多说,我们直接来分析吧:

可以看到,在第一个if分支中判断beanFactory是否是接口BeanDefinitionRegistry的实现类。

不知道大家还记得之前我们看到beanFactory初始化时,beanFactory默认是初始化了DefaultListableBeanFactory的类型,而DefaultListableBeanFactory的类继承图,我们可以再来回顾下:

可以看到,DefaultListableBeanFactory是实现了最右边的接口BeanDefinitionRegistry的,所以第一个if分支成立。

而且,我们可以看到,其实接口BeanFactoryPostProcessor中的postProcessBeanFactory方法参数类型为ConfigurableListableBeanFactory,而ConfigurableListableBeanFactory恰好也是DefaultListableBeanFactory实现的接口之一。

所以,我们才可以通过ConfigurableListableBeanFactory获取到beanFactory,所以,这些细节大家需要留个心眼,毕竟在Spring的类继承体系中各种接口和类实在是让人眼花缭乱。

BeanDefinitionRegistryPostProcessor和BeanFactoryPostProcessor

我们接着继续看到刚才的代码:

可以看到,在if分支中先初始化了两个集合,分别是用来存放BeanFactoryPostProcessor的集合regularPostProcessors,以及存放BeanDefinitionRegistryPostProcessor的集合registryProcessors。

看到这里可能有些同学就有点懵了,BeanFactoryPostProcessor上一节我们了解了是工厂级别的后处理器,可以让我们在实例化bean之前修改bean的定义BeanDefinition,但是BeanDefinitionRegistryPostProcessor又是什么呢?

我们也结合一张类继承图来了解下:

可以看到,其实BeanDefinitionRegistryPostProcessor只是一个继承BeanFactoryPostProcessor的接口而已,它里面也有一个方法postProcessBeanDefinitionRegistry,并且方法的参数类型为BeanDefinitionRegistry。

结合图片我们可以看到,在BeanDefinitionRegistry中定义了一系列和BeanDefinition相关的方法,包括对BeanDefinition的注册、查询或删除的操作,而且,通过类BeanDefinitionRegistry的名称我们可以断定方法postProcessBeanDefinitionRegistry,一般是用来注册新的BeanDefinition的。

从这里我们也可以感知到,原来Spring容器中的BeanDefinition并不一定是要从xml中解析得来,我们也可以自定义BeanDefinition,通过BeanDefinitionRegistryPostProcessor的接口方法postProcessBeanDefinitionRegistry注入到Spring容器中。

处理参数中的BeanFactoryPostProcessor

了解完BeanDefinitionRegistryPostProcessor和BeanFactoryPostProcessor的区别之后,我们继续来分析下刚才的代码:

当初始化完两个集合之后,紧接着就开始遍历参数beanFactoryPostProcessors,做的事情也非常简单,也就是将BeanDefinitionRegistryPostProcessor和BeanFactoryPostProcessor分别存放到相应的集合中。

但是,在存放接口BeanDefinitionRegistryPostProcessor的实现类到集合之前,会预先执行接口中的方法postProcessBeanDefinitionRegistry,将要注册的BeanDefinition先注册到Spring容器中,然后父类中的方法postProcessBeanFactory留到后面统一再处理。

以上代码,就是就是对方法传进来的参数beanFactoryPostProcessors的处理,接下来,我们开始处理beanFactory中的BeanFactoryPostProcessor了,毕竟,我们刚才案例中的例子中都是配置在xml中的,最终会以BeanDefinition的形式注册到容器beanFactory中。

处理容器中实现BeanDefinitionRegistryPostProcessor接口,同时又实现PriorityOrdered接口的类

接下来,我们来看下一个部分的代码:

可以看到,首先会创建了一个用于存放BeanDefinitionRegistryPostProcessor的集合currentRegistryProcessors,currentRegistryProcessors大家后面也可以看到它是阶段性会清空的,每处理完一批数据会清空一批,是一个临时存放数据的集合。

紧接着,我们就可以看到会通过beanFactory,获取Spring容器beanFactory中所有BeanDefinitionRegistryPostProcessor类型的bean的名称,然后形成一个String数组postProcessorNames,而且,我们可以看到优先处理的是实现接口BeanDefinitionRegistryPostProcessor的类。

接下来就是一个for循环,开始遍历数组postProcessorNames,for循环中的逻辑比较简单就是筛选出这些BeanDefinitionRegistryPostProcessor中,还有哪些BeanDefinitionRegistryPostProcessor同时实现了接口PriorityOrdered,并将这些类都存放在集合currentRegistryProcessors中准备即将处理它们。

另外,我们可以看到还会将这些bean的名称存放到集合processedBeans中,processedBeans在整个方法中是用于去重判断的,以防止某些BeanFactoryPostProcessor被重复处理。

我们往下看:

接下来会调用方法sortPostProcessors,对currentRegistryProcessors中的类进行排序,我们都知道当前获取到的这些类是实现了接口PriorityOrdered的,那接口PriorityOrdered是干什么的呢?

我们可以先来看下PriorityOrdered的类继承图:

可以看到接口PriorityOrdered里面什么也没有,只是继承了接口Ordered,并且接口Ordered中只有一个方法getOrder,那Spring为什么要设计这两个接口出来呢?

我们从PriorityOrdered和Ordered的类名称也能看出一点,那就是顺序和优先级,也就是说在Spring中有大量的类都实现了接口BeanDefinitionRegistryPostProcessor,那么在执行的时候肯定就会存在优先级也就是哪个先执行哪个后执行的问题。

默认情况下,实现接口PriorityOrdered的优先级比实现了接口Ordered的优先级高,如果同时实现PriorityOrdered接口或Ordered接口,那就看getOrder方法返回的结果哪个值更小,值更小的那个实现类优先级更高。

了解到这里,我们再看刚才的代码就好理解多了,我们再把视线拉回来:

可以看到,接下来就是调用方法sortPostProcessors对集合currentRegistryProcessors进行排序,集合currentRegistryProcessors中的这些类都是实现接口PriorityOrdered的,所以会根据getOrder方法的返回值进行排序,值越小优先级越大。

然后,将集合currentRegistryProcessors中的数据,像我们刚才处理参数beanFactoryPostProcessors一样存放到集合registryProcessors中,方便后续统一执行剩下的方法postProcessBeanFactory。

接着会调用方法invokeBeanDefinitionRegistryPostProcessors,在方法中先执行BeanDefinitionRegistryPostProcessor中的方法postProcessBeanDefinitionRegistry。

最后,实现了接口PriorityOrdered的BeanDefinitionRegistryPostProcessor都已经处理完了,会清空集合currentRegistryProcessors并准备处理下一批数据。

处理容器中实现BeanDefinitionRegistryPostProcessor接口,同时又实现Ordered接口的类

理解了上面这些逻辑,接下来就很好理解了,我们继续看下一个阶段的代码:

刚才我们已经处理beanFactory中实现了PriorityOrdered接口的BeanDefinitionRegistryPostProcessor。

现在,我们可以看到接下来的代码逻辑基本和我们前面分析的一样,只不过,现在处理的并不是实现接口PriorityOrdered的BeanDefinitionRegistryPostProcessor了,而是处理实现了接口Ordered的BeanDefinitionRegistryPostProcessor。

现在,实现了接口PriorityOrdered和Ordered的BeanDefinitionRegistryPostProcessor都处理完了,那最后应该处理的,就是接口PriorityOrdered和Ordered都没有实现的BeanDefinitionRegistryPostProcessor了,我们来看下会如何处理:

可以看到,果然在while循环当中不断的从beanFactory获取接口BeanDefinitionRegistryPostProcessor的实现类,并且之前前面处理过的类,都会通过代码  if (!processedBeans.contains(ppName))   判断后给剔除掉。

也就是剔除掉实现接口PriorityOrdered和Ordered的BeanDefinitionRegistryPostProcessor,剩下的就是处理没有实现这两个接口的,也就是普通的无序的BeanDefinitionRegistryPostProcessor了。

我们再看下后面的代码:

可以看到,之前在集合registryProcessors及regularPostProcessors记录的BeanFactoryPostProcessor,此时都分别在方法invokeBeanFactoryPostProcessors中,统一调用方法postProcessBeanFactory来修改BeanDefinition。

分析到这里,BeanDefinitionRegistryPostProcessor中的两个方法,算是全部都执行完了。从这里,我们就可以初步总结出一些东西了:

(1)首先处理参数中的beanFactoryPostProcessors按两种类型处理,分别是实现了接口BeanDefinitionRegistryPostProcessor的BeanFactoryPostProcessor,以及没实现该接口普通BeanFactoryPostProcessor,它们分别存放在集合registryProcessors和regularPostProcessors中。

(2)如果实现了接口BeanDefinitionRegistryPostProcessor,率先会调用BeanDefinitionRegistryPostProcessor中的方法postProcessBeanDefinitionRegistry来注册一些BeanDefinition。

(3)参数中的beanFactoryPostProcessors处理完毕之后,接着处理容器beanFactory中的BeanFactoryPostProcessor,优先从容器beanFactory中获取实现了接口BeanDefinitionRegistryPostProcessor的类,并且按照以下三种类型来处理:

分别是实现了接口PriorityOrdered、Ordered以及这两个接口都没有实现的无序的普通类,和前面一样这三种类型的类都是实现了接口BeanDefinitionRegistryPostProcessor的,优先执行BeanDefinitionRegistryPostProcessor中的方法postProcessBeanDefinitionRegistry,注册一些自定义的BeanDefinition。

(4)最后会统一执行BeanDefinitionRegistryPostProcessor的父类,以及普通BeanFactoryPostProcessor类中的方法postProcessBeanFactory,完成一些自定义的修改BeanDefinition操作。

处理容器中其他实现BeanFactoryPostProcessor接口的类

现在,我们现在已经分析了beanFactory中是如何处理实现了接口BeanDefinitionRegistryPostProcessor的类,接下来只剩下最后一种场景了,那就是处理只实现接口BeanFactoryPostProcessor的类,相信大家理解完以上的内容之后,接下来的代码分析会容易理解的多。

我们可以预料到的是,接口BeanFactoryPostProcessor的实现类也会按照三种类型来处理,分别是实现了PriorityOrdered、Ordered以及这两个接口都没实现的无序普通类型。

接下来,我们带着这个预期一起来看下吧:

果然发现按照我们刚说的三种类型,也就是实现了PriorityOrdered接口、实现了Ordered接口以及这两个接口都没有实现的情况,分别从容器beanFactory获取相应的BeanFactoryPostProcessor实现类。

并且,我们看到首先会排序并处理这三种类型中,实现了接口PriorityOrdered的BeanFactoryPostProcessor实现类,从这里也能看出实现了接口PriorityOrdered的优先级最高。

我们继续往下看:

最后,我们可以看到开始处理剩下两种类型的BeanFactoryPostProcessor。

并且,在处理的最后会清理beanFactory的元数据缓存,毕竟在工厂级别的后处理器BeanFactoryPostProcessor中,各种元数据的修改那都是在所难免的。

可以看到,在这个环节当中主要处理容器beanFactory中,单纯实现接口BeanFactoryPostProcessor的实现类,和处理接口BeanDefinitionRegistryPostProcessor实现类一样,BeanFactoryPostProcessor的处理分为三种类型来处理,分别是实现了PriorityOrdered接口、Ordered接口以及这两种接口都没实现的普通类,也就是无序的。

总结

好了,今天的知识点我们就讲到这里了,我们来总结一下吧。

一张图来梳理下当前的流程:

这一节,我们主要了解了一下BeanFactoryPostProcessor的实现类是如何处理的,代码的逻辑确实非常的繁琐。

处理优先级最高的,是参数中的BeanFactoryPostProcessor,其次是容器beanFactory中的BeanFactoryPostProcessor,这是第一批要处理的BeanFactoryPostProcessor。

第二批要处理的BeanFactoryPostProcessor,是beanFactory中的BeanDefinitionRegistryPostProcessor,beanFactory中的BeanDefinitionRegistryPostProcessor处理会细分为三种类型来处理,分别是实现了接口PriorityOrdered、实现了接口Ordered、以及这两个接口都没有实现的无序实现类。

其中,实现了接口PriorityOrdered或实现了接口Ordered的实现类,这两者是有序的,而这两个接口都没有实现的情况则是无序的。

第三批要处理的BeanFactoryPostProcessor,是beanFactory中的BeanFactoryPostProcessor,也会细分为三种类型来处理,分别是实现了接口PriorityOrdered、实现了接口Ordered、以及这两个接口都没有实现的无序实现类。

关键词:

下一篇: 最后一页
上一篇: 【全球独家】2023年,是思维财经&投资者网创立十五周年……

18-Spring高级容器初始化:BeanFactoryPostProcessor如何执行

【全球独家】2023年,是思维财经&投资者网创立十五周年……

青萝卜补铁,萝卜干补铁

当前播报:容大感光:预计上半年归母净利同比增98%-128%

在中国当“岛主”,门槛不低当好更难|每日视点

天天最新:美非裔奥运冠军死于分娩 美媒:孕产妇死亡率仍有巨大种族差异

天天快播:山不碍路,路自通山

如果她还在,应该写下很多本日记了……|精选

全球微速讯:芭乐果的籽能吃吗 芭乐果的正确吃法

怀疑被偷拍了如何合理维权?一图读懂

台退将群聚迎黄埔建校百年 侯友宜争取支持|全球新动态

今日热文:供热通风与空调工程技术可以考哪些大学 供热通风与空调工程技术学校排名

屏南县气象台发布雷电黄色预警信号 【2023-06-17】

环球实时:利用电脑如何赚钱_利用电脑赚钱的5种方法

全球短讯!重庆180余项创新成果集中“招亲”

世界观热点:凯森福景美地广场广场舞噪音扰民

插上数字之翼,国产“智”造飞入千行百业_全球时快讯

全球观速讯丨道路养护与管理可以考哪些大学 道路养护与管理学校排名

全球热门:lol陈赫俄洛伊_lol陈赫

李国瑞(关于李国瑞的简介)_每日播报

热头条丨火箭的速度比声音快吗_火箭的速度

土耳其记者:尤文首次报价扎尼奥洛,想将麦肯尼加入交易-环球快播

护航大运会 安全“大练兵”!2023年成都网络安全技能赛即将开战

win10电脑声音怎么设置_电脑声音怎么设置

陈梦豪爽!买3大包海底捞回宿舍,王艺迪跟班拎包,张瑞提1兜开路 环球微头条

全球首台!16兆瓦超大容量海上风电主机在福建福清吊装

全球视点!商业 | LE LABO正式入驻上海,带来哪些新体验?

周末就是618,酒类市场紧锣密鼓线上促销忙 简讯

区领导调研金汇镇

乒坛大爆冷!男单2号种子一轮游,曾吊打梁靖崑,4-0打哭张本智和

乡村小学创新教育交流会举行:聚焦乡村教育高质量发展

《表白吧!在毕业前》公映 治愈青春勇敢做自己 世界消息

全球观察:中国电科院:2030-2060年我国电力需求响应比例将提高四倍

热点在线丨建筑胶黏剂与密封胶应手册

父母房产继承法2021年新规定可以卖吗

每日视讯:Uzi复出首秀万众瞩目,EDG对阵iG小狗有望首胜,TES冲击五连胜!