最美情侣中文字幕电影,在线麻豆精品传媒,在线网站高清黄,久久黄色视频

歡迎光臨散文網(wǎng) 會員登陸 & 注冊

19-Spring高級容器初始化:BeanPostProcessor是如何注冊的呢?

2023-06-18 18:49 作者:儒猿課堂  | 我要投稿

開篇

前面我們已經(jīng)了解了BeanFactoryPostProcessor,它可以在Spring容器的層面對BeanDefinition進行修改,可以說BeanFactoryPostProcessor是在Spring容器層面的一個擴展。


但是,我們有沒有粒度更小一點的擴展處理呢?比如我們能否在bean的層面進行精準的把控呢?答案當然是有的,這一節(jié)我們繼續(xù)順著refresh方法,來看下Spring中另外一個比較重要的擴展點,也就是bean的后處理器BeanPostProcessor,主要包括以下幾個部分:

1.首先來認識下Spring中什么是BeanPostProcessor

2.再來看下BeanPostProcessor一般是如何使用的

3.最后我們來分析下ApplicationContext初始化時,BeanPostProcessor是如何注冊的


初識BeanPostProcessor

前面,我們已經(jīng)了解了方法invokeBeanFactoryPostProcessors是如何執(zhí)行Spring容器中的各種工廠后處理器BeanFactoryPostProcessor。

接下來,我們再看到refresh方法中,下一個方法registerBeanPostProcessors:

我們到方法registerBeanPostProcessors里面看下:

可以看到,在方法registerBeanPostProcessors里面又委托了PostProcessorRegistrationDelegate來調(diào)用方法registerBeanPostProcessors,通過方法名稱我們可以知道,接下來應(yīng)該是要注冊BeanPostProcessor。


在繼續(xù)源碼分析之前,我們有必要來了解一下BeanPostProcessor是什么,BeanPostProcessor像我們前面說的一樣,它就是在bean的層面對bean實例化的一個擴展,也就是說通過BeanPostProcessor可以控制Spring容器中任意一個bean的實例化過程。

什么意思呢?我們結(jié)合著BeanPostProcessor的類圖來輔助理解bean實例化的控制過程:

可以看到,在接口BeanPostProcessor中有兩個方法,分別是方法postProcessBeforeInitialization和方法postProcessAfterInitialization,通過方法的名稱我們大概可以知道,這兩個方法分別是在bean實例初始化前和初始化后執(zhí)行的。

那bean的初始化和實例化又有什么關(guān)系呢?因為bean實例化和初始化這塊源碼的邏輯,目前我們還沒有分析到那里,其實如果往細的來說,bean實例化完成之后還會經(jīng)歷初始化這個階段,經(jīng)歷過初始化階段的bean實例,才算完全創(chuàng)建好了,而接口BeanPostProcessor中的兩個接口方法,則分別是在bean初始化前后執(zhí)行的。


從整體上來看,BeanPostProcessor是影響bean實例化的一個非常重要的因素,比如后面我們講到的AOP代理對象,如果我們要對一個bean通過動態(tài)代理方式創(chuàng)建,Spring底層其實就是以接口BeanPostProcessor的后處理方法來作為入口創(chuàng)建的,這塊邏輯后面我們也會講到。

這樣的話,就算先前已經(jīng)通過Spring默認的一套實例化邏輯,將bean實例化好了,但是,在bean初始化階段執(zhí)行到了接口BeanPostProcessor的后處理方法,也會重新按照AOP的那套代理邏輯來實例化對象。

所以,我們暫且可以理解為接口BeanPostProcessor是用于介入一個bean的實例化的,而bean實例化和初始化階段相關(guān)的細節(jié)源碼,后面我們也會看到的,到時候大家理解起來就清晰多了。


BeanPostProcessor簡單使用

我們通過一個案例來體驗下BeanPostProcessor一般是如何使用的:

可以看到,首先我們自定義了一個類StudentPostProcessor并實現(xiàn)接口BeanPostProcessor,同時實現(xiàn)了方法postProcessBeforeInitialization和postProcessAfterInitialization。

然后,我們分別在這兩個方法中添加了一些邏輯,很明顯StudentPostProcessor是用來影響Student實例化過程的,然后,我們再把StudentPostProcessor配置到xml中:

StudentPostProcessor和Student一起通過bean標簽配置好了,我們可以預(yù)料到的是,如果外界需要使用Student對象時,可以通過getBean方法獲取Student對象。


這個時候就會觸發(fā)bean的實例化,Spring容器就會取出名稱為student的BeanDefinition,然后實例化一個Student對象出來,在實例化之前,根據(jù)我們剛才的分析就會先獲取Spring容器中所有的BeanPostProcessor,包括我們剛配置在xml中的StudentPostProcessor。

然后在實例化Student之前,先執(zhí)行StudentPostProcessor中的方法postProcessBeforeInitialization,與之對應(yīng)的是,在Student實例化完成之后,最后會執(zhí)行StudentPostProcessor的postProcessAfterInitialization方法,做一些善后的工作。


我們寫段代碼來驗證一下:

代碼很簡單,運行下看下效果:

可以看到,果然按照我們預(yù)期的那樣,getBean方法觸發(fā)bean的實例化過程創(chuàng)建Student對象,在實例化的前后,分別執(zhí)行方法postProcessBeforeInitialization和方法postProcessAfterInitialization,打印出我們預(yù)期的信息。


通過向Spring容器注冊各種各樣的BeanPostProcessor,我們可以對任意一個我們想要控制實例化的bean,添加我們想要的邏輯,從而人為介入并控制bean的實例化過程。

比如,我們創(chuàng)建也就是實例化一個bean,到底是直接通過關(guān)鍵字new出來呢?還是通過JDK動態(tài)代理或CGLIB動態(tài)代理呢?這些都是bean實例化的候選方式,我們可以在bean的后處理器BeanPostProcessor方法中,決定bean到底應(yīng)該是用哪種方式來實例化bean的。


BeanPostProcessor的注冊

了解完BeanPostProcessor之后,我們接著剛才的流程繼續(xù)來看下Spring是如何注冊BeanPostProcessor的:

我們到方法registerBeanPostProcessors中看下:

可以看到,這里的代碼量依然非常的壯觀,但是,和上一講的代碼量相比已經(jīng)大大減少了,而且,如果我們理解了上一講的方法邏輯,接下來的代碼理解將會變得非常簡單,我們還是一步步來各個擊破。


首先,我們先來看下第一個區(qū)域的代碼:

可以看到,首先從beanFactory中獲取所有接口BeanPostProcessor的實現(xiàn)類的名稱,然后率先往beanFactory中,添加了一個bean后處理器BeanPostProcessorChecker。

BeanPostProcessorChecker的功能,其實就是簡單檢查下哪些bean是沒有資格讓所有BeanPostProcessor處理它的,并記錄一下日志信息而已,這塊代碼并不是很重要我們姑且先跳過。

接著,我們看到了熟悉的一幕:

可以看到初始化了好幾個集合,類比我們上節(jié)課的分析,我們可以很清晰的知道這些集合中,priorityOrderedPostProcessors是存放實現(xiàn)了接口PriorityOrdered的BeanPostProcessor,orderedPostProcessorNames存放實現(xiàn)了接口Ordered的BeanPostProcessor,而nonOrderedPostProcessorNames則存放無序的普通的BeanPostProcessor。

而集合internalPostProcessors比較特殊,是用于存放Spring容器內(nèi)部,在解析各種注解時臨時生成的BeanPostProcessor,比如解析@Autowired注解時就會生成,后續(xù)我們分析到注解相關(guān)的源碼時就可以看到了,所以,這部分的BeanFactoryProcessor也是要注冊的。


我們繼續(xù)往后面看,基本上大家也能輕易看得懂了:

首先,和我們預(yù)期的一樣,將beanFactory中的各種類型的BeanPostProcessor進行歸類放到不同的集合當中,和我們上一節(jié)看到的代碼結(jié)構(gòu)基本是一樣的。


首先將實現(xiàn)了PriorityOrdered接口、Ordered接口、以及這兩個接口都沒實現(xiàn)的普通無序BeanPostProcessor接口實現(xiàn)類,將這三種類型的BeanPostProcessor都放到相應(yīng)的集合中。

其中,如果發(fā)現(xiàn)BeanPostProcessor實現(xiàn)類實現(xiàn)了MergedBeanDefinitionPostProcessor,就放到集合internalPostProcessors中,被認定是Spring內(nèi)部生成的BeanPostProcessor。


而且,我們接著看到率先對實現(xiàn)接口PriorityOrdered的實現(xiàn)類進行排序和注冊,需要注意一點的是這里只是將BeanPostProcessor注冊到Spring容器beanFactory中,而不是像BeanFactoryPostProcessor一樣立馬就執(zhí)行方法了,BeanPostProcessor中的方法是在bean實例化的時候執(zhí)行的。

我們再看一下最后一些代碼:

可以看到,接下來就是依次處理剩下幾個集合中的BeanPostProcessor,當然,在這個過程當中我們看到還會篩選出Spring容器內(nèi)部的BeanPostProcessor,并放到集合internalPostProcessors中。

最終,internalPostProcessors中的BeanPostProcessor會在最后被注冊到容器beanFactory中,整體的代碼結(jié)構(gòu)和上一節(jié)的是非常類似的。

總結(jié)


好了,今天的知識點我們就講到這里了,我們來總結(jié)一下吧。

一張圖來梳理下當前的流程:

到這里,我們已經(jīng)分析bean的后處理器BeanPostProcessor的注冊,注冊的邏輯的代碼結(jié)構(gòu)和上一節(jié)BeanFactoryPostProcessor的極為的相似,但是更加的簡潔。

首先,從容器beanFactory中,獲取所有實現(xiàn)接口BeanPostProcessor的bean名稱,然后再按照實現(xiàn)PriorityOrdered接口、實現(xiàn)Ordered接口以及普通無序的BeanPostProcessor這三種類型,依次從beanFactory中獲取到相應(yīng)的實現(xiàn)類,再注冊到beanFactory中。


這處理以上這三種類型的BeanPostProcessor的同時,會判斷一下這些BeanPostProcessor的實現(xiàn)類中,是否存在同時實現(xiàn)接口MergedBeanDefinitionPostProcessor的類,并及時記錄到集合internalPostProcessors中。


最后,會一并注冊到beanFactory的BeanPostProcessor調(diào)用鏈的末尾,很顯然Spring內(nèi)部的BeanPostProcessor的優(yōu)先級是最低的。


19-Spring高級容器初始化:BeanPostProcessor是如何注冊的呢?的評論 (共 條)

分享到微博請遵守國家法律
承德市| 西城区| 吉林市| 油尖旺区| 苍山县| 两当县| 和田县| 陵川县| 昆山市| 虞城县| 开江县| 峨眉山市| 海淀区| 大邑县| 衡山县| 普安县| 新宁县| 塔城市| 长岛县| 二连浩特市| 汝南县| 会泽县| 焦作市| 阿城市| 尼勒克县| 宕昌县| 积石山| 余干县| 香港| 辽中县| 萨嘎县| 德保县| 镇江市| 卓尼县| 中方县| 高阳县| 宁城县| 上林县| 涿鹿县| 鱼台县| 桂阳县|