18-Spring高級容器初始化:BeanFactoryPostProcessor如何執(zhí)行

開篇
上一節(jié),我們了解了空實(shí)現(xiàn)方法postProcessBeanFactory的作用以及什么是BeanFactoryPostProcessor,同時也自定義實(shí)現(xiàn)了它們,體驗(yàn)了下在實(shí)際開發(fā)過程中一般是如何使用它們的。
這一節(jié),我們的目標(biāo)就是要搞清楚在ApplicationContext初始化時,所有的工廠后處理器BeanFactoryPostProcessors中的方法是如何執(zhí)行的,主要分為以下幾個部分:
1.首先來看下Spring是如何處理參數(shù)傳進(jìn)來的BeanFactoryPostProcessor接口實(shí)現(xiàn)類
2.然后再看下Spring容器中,實(shí)現(xiàn)了接口BeanDefinitionRegistryPostProcessor的BeanFactoryPostProcessor接口實(shí)現(xiàn)類是如何處理的
3.最后再來看下Spring容器中,僅僅只是實(shí)現(xiàn)了BeanFactoryPostProcessor接口的實(shí)現(xiàn)類是如何處理的
初探方法invokeBeanFactoryPostProcessors
我們回到上節(jié)課分析的位置,繼續(xù)來看下:

可以看到,首先會通過方法getBeanFactoryPostProcessors獲取參數(shù)中的工廠后處理器BeanFactoryPostProcessor,然后調(diào)用方法invokeBeanFactoryPostProcessors執(zhí)行工廠后處理器中的方法。
我們跟進(jìn)到方法invokeBeanFactoryPostProcessors中看下:

可以看到,一眼看過去方法invokeBeanFactoryPostProcessors中的邏輯實(shí)在是太復(fù)雜了。
但是,我們既然是研究Spring的源碼,還是很有必要來分析下的,所以,接下來大家務(wù)必要耐下心來,為了方便截圖,我們將這個方法中的代碼分為多個片段逐步來分析。
簡單觀察了一下方法invokeBeanFactoryPostProcessors之后發(fā)現(xiàn),其實(shí)是因?yàn)榉椒ɡ锩娉涑庵罅恐貜?fù)的代碼,我們只要把前面一小部分的代碼理解透了之后,后面的邏輯梳理起來也就很簡單了。
話不多說,我們直接來分析吧:

可以看到,在第一個if分支中判斷beanFactory是否是接口BeanDefinitionRegistry的實(shí)現(xiàn)類。
不知道大家還記得之前我們看到beanFactory初始化時,beanFactory默認(rèn)是初始化了DefaultListableBeanFactory的類型,而DefaultListableBeanFactory的類繼承圖,我們可以再來回顧下:

可以看到,DefaultListableBeanFactory是實(shí)現(xiàn)了最右邊的接口BeanDefinitionRegistry的,所以第一個if分支成立。
而且,我們可以看到,其實(shí)接口BeanFactoryPostProcessor中的postProcessBeanFactory方法參數(shù)類型為ConfigurableListableBeanFactory,而ConfigurableListableBeanFactory恰好也是DefaultListableBeanFactory實(shí)現(xiàn)的接口之一。
所以,我們才可以通過ConfigurableListableBeanFactory獲取到beanFactory,所以,這些細(xì)節(jié)大家需要留個心眼,畢竟在Spring的類繼承體系中各種接口和類實(shí)在是讓人眼花繚亂。
BeanDefinitionRegistryPostProcessor和BeanFactoryPostProcessor
我們接著繼續(xù)看到剛才的代碼:

可以看到,在if分支中先初始化了兩個集合,分別是用來存放BeanFactoryPostProcessor的集合regularPostProcessors,以及存放BeanDefinitionRegistryPostProcessor的集合registryProcessors。
看到這里可能有些同學(xué)就有點(diǎn)懵了,BeanFactoryPostProcessor上一節(jié)我們了解了是工廠級別的后處理器,可以讓我們在實(shí)例化bean之前修改bean的定義BeanDefinition,但是BeanDefinitionRegistryPostProcessor又是什么呢?
我們也結(jié)合一張類繼承圖來了解下:

可以看到,其實(shí)BeanDefinitionRegistryPostProcessor只是一個繼承BeanFactoryPostProcessor的接口而已,它里面也有一個方法postProcessBeanDefinitionRegistry,并且方法的參數(shù)類型為BeanDefinitionRegistry。
結(jié)合圖片我們可以看到,在BeanDefinitionRegistry中定義了一系列和BeanDefinition相關(guān)的方法,包括對BeanDefinition的注冊、查詢或刪除的操作,而且,通過類BeanDefinitionRegistry的名稱我們可以斷定方法postProcessBeanDefinitionRegistry,一般是用來注冊新的BeanDefinition的。
從這里我們也可以感知到,原來Spring容器中的BeanDefinition并不一定是要從xml中解析得來,我們也可以自定義BeanDefinition,通過BeanDefinitionRegistryPostProcessor的接口方法postProcessBeanDefinitionRegistry注入到Spring容器中。
處理參數(shù)中的BeanFactoryPostProcessor
了解完BeanDefinitionRegistryPostProcessor和BeanFactoryPostProcessor的區(qū)別之后,我們繼續(xù)來分析下剛才的代碼:

當(dāng)初始化完兩個集合之后,緊接著就開始遍歷參數(shù)beanFactoryPostProcessors,做的事情也非常簡單,也就是將BeanDefinitionRegistryPostProcessor和BeanFactoryPostProcessor分別存放到相應(yīng)的集合中。
但是,在存放接口BeanDefinitionRegistryPostProcessor的實(shí)現(xiàn)類到集合之前,會預(yù)先執(zhí)行接口中的方法postProcessBeanDefinitionRegistry,將要注冊的BeanDefinition先注冊到Spring容器中,然后父類中的方法postProcessBeanFactory留到后面統(tǒng)一再處理。
以上代碼,就是就是對方法傳進(jìn)來的參數(shù)beanFactoryPostProcessors的處理,接下來,我們開始處理beanFactory中的BeanFactoryPostProcessor了,畢竟,我們剛才案例中的例子中都是配置在xml中的,最終會以BeanDefinition的形式注冊到容器beanFactory中。
處理容器中實(shí)現(xiàn)BeanDefinitionRegistryPostProcessor接口,同時又實(shí)現(xiàn)PriorityOrdered接口的類
接下來,我們來看下一個部分的代碼:

可以看到,首先會創(chuàng)建了一個用于存放BeanDefinitionRegistryPostProcessor的集合currentRegistryProcessors,currentRegistryProcessors大家后面也可以看到它是階段性會清空的,每處理完一批數(shù)據(jù)會清空一批,是一個臨時存放數(shù)據(jù)的集合。
緊接著,我們就可以看到會通過beanFactory,獲取Spring容器beanFactory中所有BeanDefinitionRegistryPostProcessor類型的bean的名稱,然后形成一個String數(shù)組postProcessorNames,而且,我們可以看到優(yōu)先處理的是實(shí)現(xiàn)接口BeanDefinitionRegistryPostProcessor的類。
接下來就是一個for循環(huán),開始遍歷數(shù)組postProcessorNames,for循環(huán)中的邏輯比較簡單就是篩選出這些BeanDefinitionRegistryPostProcessor中,還有哪些BeanDefinitionRegistryPostProcessor同時實(shí)現(xiàn)了接口PriorityOrdered,并將這些類都存放在集合currentRegistryProcessors中準(zhǔn)備即將處理它們。
另外,我們可以看到還會將這些bean的名稱存放到集合processedBeans中,processedBeans在整個方法中是用于去重判斷的,以防止某些BeanFactoryPostProcessor被重復(fù)處理。
我們往下看:

接下來會調(diào)用方法sortPostProcessors,對currentRegistryProcessors中的類進(jìn)行排序,我們都知道當(dāng)前獲取到的這些類是實(shí)現(xiàn)了接口PriorityOrdered的,那接口PriorityOrdered是干什么的呢?
我們可以先來看下PriorityOrdered的類繼承圖:

可以看到接口PriorityOrdered里面什么也沒有,只是繼承了接口Ordered,并且接口Ordered中只有一個方法getOrder,那Spring為什么要設(shè)計(jì)這兩個接口出來呢?
我們從PriorityOrdered和Ordered的類名稱也能看出一點(diǎn),那就是順序和優(yōu)先級,也就是說在Spring中有大量的類都實(shí)現(xiàn)了接口BeanDefinitionRegistryPostProcessor,那么在執(zhí)行的時候肯定就會存在優(yōu)先級也就是哪個先執(zhí)行哪個后執(zhí)行的問題。
默認(rèn)情況下,實(shí)現(xiàn)接口PriorityOrdered的優(yōu)先級比實(shí)現(xiàn)了接口Ordered的優(yōu)先級高,如果同時實(shí)現(xiàn)PriorityOrdered接口或Ordered接口,那就看getOrder方法返回的結(jié)果哪個值更小,值更小的那個實(shí)現(xiàn)類優(yōu)先級更高。
了解到這里,我們再看剛才的代碼就好理解多了,我們再把視線拉回來:

可以看到,接下來就是調(diào)用方法sortPostProcessors對集合currentRegistryProcessors進(jìn)行排序,集合currentRegistryProcessors中的這些類都是實(shí)現(xiàn)接口PriorityOrdered的,所以會根據(jù)getOrder方法的返回值進(jìn)行排序,值越小優(yōu)先級越大。
然后,將集合currentRegistryProcessors中的數(shù)據(jù),像我們剛才處理參數(shù)beanFactoryPostProcessors一樣存放到集合registryProcessors中,方便后續(xù)統(tǒng)一執(zhí)行剩下的方法postProcessBeanFactory。
接著會調(diào)用方法invokeBeanDefinitionRegistryPostProcessors,在方法中先執(zhí)行BeanDefinitionRegistryPostProcessor中的方法postProcessBeanDefinitionRegistry。
最后,實(shí)現(xiàn)了接口PriorityOrdered的BeanDefinitionRegistryPostProcessor都已經(jīng)處理完了,會清空集合currentRegistryProcessors并準(zhǔn)備處理下一批數(shù)據(jù)。
處理容器中實(shí)現(xiàn)BeanDefinitionRegistryPostProcessor接口,同時又實(shí)現(xiàn)Ordered接口的類
理解了上面這些邏輯,接下來就很好理解了,我們繼續(xù)看下一個階段的代碼:

剛才我們已經(jīng)處理beanFactory中實(shí)現(xiàn)了PriorityOrdered接口的BeanDefinitionRegistryPostProcessor。
現(xiàn)在,我們可以看到接下來的代碼邏輯基本和我們前面分析的一樣,只不過,現(xiàn)在處理的并不是實(shí)現(xiàn)接口PriorityOrdered的BeanDefinitionRegistryPostProcessor了,而是處理實(shí)現(xiàn)了接口Ordered的BeanDefinitionRegistryPostProcessor。
現(xiàn)在,實(shí)現(xiàn)了接口PriorityOrdered和Ordered的BeanDefinitionRegistryPostProcessor都處理完了,那最后應(yīng)該處理的,就是接口PriorityOrdered和Ordered都沒有實(shí)現(xiàn)的BeanDefinitionRegistryPostProcessor了,我們來看下會如何處理:

可以看到,果然在while循環(huán)當(dāng)中不斷的從beanFactory獲取接口BeanDefinitionRegistryPostProcessor的實(shí)現(xiàn)類,并且之前前面處理過的類,都會通過代碼 ?if (!processedBeans.contains(ppName)) ? 判斷后給剔除掉。
也就是剔除掉實(shí)現(xiàn)接口PriorityOrdered和Ordered的BeanDefinitionRegistryPostProcessor,剩下的就是處理沒有實(shí)現(xiàn)這兩個接口的,也就是普通的無序的BeanDefinitionRegistryPostProcessor了。
我們再看下后面的代碼:

可以看到,之前在集合registryProcessors及regularPostProcessors記錄的BeanFactoryPostProcessor,此時都分別在方法invokeBeanFactoryPostProcessors中,統(tǒng)一調(diào)用方法postProcessBeanFactory來修改BeanDefinition。
分析到這里,BeanDefinitionRegistryPostProcessor中的兩個方法,算是全部都執(zhí)行完了。從這里,我們就可以初步總結(jié)出一些東西了:
(1)首先處理參數(shù)中的beanFactoryPostProcessors按兩種類型處理,分別是實(shí)現(xiàn)了接口BeanDefinitionRegistryPostProcessor的BeanFactoryPostProcessor,以及沒實(shí)現(xiàn)該接口普通BeanFactoryPostProcessor,它們分別存放在集合registryProcessors和regularPostProcessors中。
(2)如果實(shí)現(xiàn)了接口BeanDefinitionRegistryPostProcessor,率先會調(diào)用BeanDefinitionRegistryPostProcessor中的方法postProcessBeanDefinitionRegistry來注冊一些BeanDefinition。
(3)參數(shù)中的beanFactoryPostProcessors處理完畢之后,接著處理容器beanFactory中的BeanFactoryPostProcessor,優(yōu)先從容器beanFactory中獲取實(shí)現(xiàn)了接口BeanDefinitionRegistryPostProcessor的類,并且按照以下三種類型來處理:
分別是實(shí)現(xiàn)了接口PriorityOrdered、Ordered以及這兩個接口都沒有實(shí)現(xiàn)的無序的普通類,和前面一樣這三種類型的類都是實(shí)現(xiàn)了接口BeanDefinitionRegistryPostProcessor的,優(yōu)先執(zhí)行BeanDefinitionRegistryPostProcessor中的方法postProcessBeanDefinitionRegistry,注冊一些自定義的BeanDefinition。
(4)最后會統(tǒng)一執(zhí)行BeanDefinitionRegistryPostProcessor的父類,以及普通BeanFactoryPostProcessor類中的方法postProcessBeanFactory,完成一些自定義的修改BeanDefinition操作。
處理容器中其他實(shí)現(xiàn)BeanFactoryPostProcessor接口的類
現(xiàn)在,我們現(xiàn)在已經(jīng)分析了beanFactory中是如何處理實(shí)現(xiàn)了接口BeanDefinitionRegistryPostProcessor的類,接下來只剩下最后一種場景了,那就是處理只實(shí)現(xiàn)接口BeanFactoryPostProcessor的類,相信大家理解完以上的內(nèi)容之后,接下來的代碼分析會容易理解的多。
我們可以預(yù)料到的是,接口BeanFactoryPostProcessor的實(shí)現(xiàn)類也會按照三種類型來處理,分別是實(shí)現(xiàn)了PriorityOrdered、Ordered以及這兩個接口都沒實(shí)現(xiàn)的無序普通類型。
接下來,我們帶著這個預(yù)期一起來看下吧:

果然發(fā)現(xiàn)按照我們剛說的三種類型,也就是實(shí)現(xiàn)了PriorityOrdered接口、實(shí)現(xiàn)了Ordered接口以及這兩個接口都沒有實(shí)現(xiàn)的情況,分別從容器beanFactory獲取相應(yīng)的BeanFactoryPostProcessor實(shí)現(xiàn)類。
并且,我們看到首先會排序并處理這三種類型中,實(shí)現(xiàn)了接口PriorityOrdered的BeanFactoryPostProcessor實(shí)現(xiàn)類,從這里也能看出實(shí)現(xiàn)了接口PriorityOrdered的優(yōu)先級最高。
我們繼續(xù)往下看:

最后,我們可以看到開始處理剩下兩種類型的BeanFactoryPostProcessor。
并且,在處理的最后會清理beanFactory的元數(shù)據(jù)緩存,畢竟在工廠級別的后處理器BeanFactoryPostProcessor中,各種元數(shù)據(jù)的修改那都是在所難免的。
可以看到,在這個環(huán)節(jié)當(dāng)中主要處理容器beanFactory中,單純實(shí)現(xiàn)接口BeanFactoryPostProcessor的實(shí)現(xiàn)類,和處理接口BeanDefinitionRegistryPostProcessor實(shí)現(xiàn)類一樣,BeanFactoryPostProcessor的處理分為三種類型來處理,分別是實(shí)現(xiàn)了PriorityOrdered接口、Ordered接口以及這兩種接口都沒實(shí)現(xiàn)的普通類,也就是無序的。
總結(jié)
好了,今天的知識點(diǎn)我們就講到這里了,我們來總結(jié)一下吧。
一張圖來梳理下當(dāng)前的流程:

這一節(jié),我們主要了解了一下BeanFactoryPostProcessor的實(shí)現(xiàn)類是如何處理的,代碼的邏輯確實(shí)非常的繁瑣。
處理優(yōu)先級最高的,是參數(shù)中的BeanFactoryPostProcessor,其次是容器beanFactory中的BeanFactoryPostProcessor,這是第一批要處理的BeanFactoryPostProcessor。
第二批要處理的BeanFactoryPostProcessor,是beanFactory中的BeanDefinitionRegistryPostProcessor,beanFactory中的BeanDefinitionRegistryPostProcessor處理會細(xì)分為三種類型來處理,分別是實(shí)現(xiàn)了接口PriorityOrdered、實(shí)現(xiàn)了接口Ordered、以及這兩個接口都沒有實(shí)現(xiàn)的無序?qū)崿F(xiàn)類。
其中,實(shí)現(xiàn)了接口PriorityOrdered或?qū)崿F(xiàn)了接口Ordered的實(shí)現(xiàn)類,這兩者是有序的,而這兩個接口都沒有實(shí)現(xiàn)的情況則是無序的。
第三批要處理的BeanFactoryPostProcessor,是beanFactory中的BeanFactoryPostProcessor,也會細(xì)分為三種類型來處理,分別是實(shí)現(xiàn)了接口PriorityOrdered、實(shí)現(xiàn)了接口Ordered、以及這兩個接口都沒有實(shí)現(xiàn)的無序?qū)崿F(xiàn)類。