spring-boot源碼分析之beanFactory · 玖

前言
今天我們開始看refresh的最核心方法,這四個(gè)方法剖析完成,spring boot就真的啟動(dòng)成功了:
onRefreshregisterListenersfinishBeanFactoryInitializationfinishRefresh
refresh
onRefresh
這個(gè)方法就是初始化特殊子類容器中的特殊bean,這個(gè)方法的具體調(diào)用流程如下:

首先它先調(diào)用了abstractApplicationContext的onRefresh方法,由于這個(gè)是個(gè)抽象類,所以實(shí)際上調(diào)用的是當(dāng)前容器或者其父類繼承了abstractApplicationContext的類的onRefresh方法,實(shí)現(xiàn)onRefresh的類總共有5個(gè):

但其中只有ServletWebServerApplicationContext是我們當(dāng)前容器的父類,所以實(shí)際上最后調(diào)用的是ServletWebServerApplicationContex的onRefresh方法,在它的方法內(nèi)部有兩部分調(diào)用,一個(gè)是調(diào)用父類的onRefresh方法,父類的方法內(nèi)部其實(shí)就是進(jìn)行了themeSource資源的初始化;另一部分,調(diào)用了createWebServer方法,顧名思義,就是創(chuàng)建web服務(wù)器。
initThemeSource
先看父類onRefresh的調(diào)用,它的內(nèi)部其實(shí)就是進(jìn)行了主題資源的初始化,準(zhǔn)確地說(shuō)就是進(jìn)行了實(shí)例化和賦值,最后將themeSource返回:

看了半天才搞明白,原來(lái)這里的themeSource指的就是主題資源,我還在納悶spring boot為啥還需要主題(就是手機(jī)桌面這種主題),最后才發(fā)現(xiàn)原來(lái)是給消息資源使用,主要包括css、圖片等資源:

createWebContext
這個(gè)方法就是為了創(chuàng)建webServer,這一點(diǎn)從名字就可以看出來(lái):

默認(rèn)情況下webServer和servletContext都是null,所以會(huì)創(chuàng)建webServer實(shí)例,默認(rèn)情況下創(chuàng)建的是TomcatWebServer的實(shí)例,創(chuàng)建完成后會(huì)往beanFactory中注冊(cè)webServer的兩個(gè)生命周期實(shí)例,一個(gè)是shutdown,一個(gè)是startStop,這兩個(gè)生命周期主要是用來(lái)控制服務(wù)啟停的。

registerListeners
這個(gè)方法就是注冊(cè)監(jiān)聽(tīng)器,而且方法注釋上也寫的很清楚:校驗(yàn)并注冊(cè)監(jiān)聽(tīng)器

內(nèi)部實(shí)現(xiàn)也很簡(jiǎn)單,首先是往應(yīng)用事件廣播器中添加監(jiān)聽(tīng)器;
然后還把監(jiān)聽(tīng)器的beanName注冊(cè)進(jìn)應(yīng)用監(jiān)聽(tīng)器的接收器(defaultRetriever)列表中,而且這里注釋的很清楚:這里不初始化FactoryBeans;
最后是推送應(yīng)用預(yù)刷新事件(也就是我們第陸部分的內(nèi)容,這里的監(jiān)聽(tīng)器是在prepareRefresh方法中進(jìn)行初始化的)

finishBeanFactoryInitialization
從名字就可以看出來(lái),這個(gè)方法就是完成最后的beanFactory初始化,方法注釋也說(shuō)的很清楚,會(huì)初始化剩余的單例bean。
方法主要有四塊內(nèi)容,第一塊是設(shè)置beanFacory的轉(zhuǎn)換服務(wù),我就說(shuō)這一塊的代碼咋看著有點(diǎn)眼熟,原來(lái)是在分析prepareContext方法的時(shí)候,當(dāng)時(shí)也有調(diào)用這個(gè)方法。
第二塊是注冊(cè)已經(jīng)嵌入的配置值的解析器,這里是lambda的寫法,這注冊(cè)的應(yīng)該是對(duì)$Value{name}這樣的配置的解析器
第三塊是獲取加載時(shí)間織入器,但是有一點(diǎn)我有點(diǎn)看不懂,getBean是有返回值的,這里也沒(méi)有接收,所以這里調(diào)用只是為了校驗(yàn)?

第四塊就是調(diào)用beanFactory的三個(gè)方法,首先是調(diào)用setTempClassLoader置為null,官方給的注釋是停止使用臨時(shí)加載器;然后調(diào)用freezeConfiguration方法,官方給的注釋是僅獲取bean的定義元數(shù)據(jù),不做其他操作;最后調(diào)用preInstantiateSingletons方法,從方法名來(lái)看這個(gè)方法會(huì)進(jìn)行單例bean的預(yù)初始化操作,官方給的注釋是實(shí)例化剩余的單例。
下面我們?cè)敿?xì)看下freezeConfiguration和preInstantiateSingletons,先看freezeConfiguration方法:

本以為這個(gè)方法內(nèi)部實(shí)現(xiàn)很復(fù)雜,點(diǎn)進(jìn)來(lái)才發(fā)現(xiàn)就兩行代碼,第一行將configurationFronzen設(shè)置為true,這個(gè)屬性用于標(biāo)記bean的定義元數(shù)據(jù)是否已經(jīng)被緩存。

第二行是將bean定義名賦值給frozenBeanDefinitionNames,從名字推測(cè)這個(gè)應(yīng)該是為了凍結(jié)bean定義名,這也就意味著在這個(gè)方法執(zhí)行之后,不會(huì)再注冊(cè)新的bean定義名。
下面我們看第四塊的第三個(gè)方法——preInstantiateSingletons,這個(gè)方法主要有兩大塊內(nèi)容,一塊是實(shí)例化非懶加載的bean(通過(guò)getBean方法,看來(lái)我對(duì)這個(gè)方法理解的不夠透徹,但是這個(gè)方法內(nèi)部并沒(méi)有進(jìn)行newInstance這樣的操作,而是直接從bean的beanFactory中獲取);
另一塊是初始化后,回調(diào)操作。這里的doPrivileged方法是java.security包下提供的一個(gè)特權(quán)操作,關(guān)于這一塊后面需要深入研究下。這個(gè)doPrivileged內(nèi)部調(diào)用了afterSingletonsInstantiated,這個(gè)方法在單例實(shí)例化完成后調(diào)用,就是我們說(shuō)的回調(diào)操作

finishRefresh
這個(gè)方法就是完成最后的清理工作,同時(shí)會(huì)初始化容器的生命周期處理器,然后執(zhí)行容器生命周期的刷新操作,最后會(huì)推送啟動(dòng)刷新完成事件

總結(jié)
緊趕慢趕,四個(gè)方法總算全部分享完了,差一點(diǎn)點(diǎn)就分析不完了,而且最后一個(gè)方法實(shí)在分析地有點(diǎn)拉垮。
總之,關(guān)于這兩天的內(nèi)容更新,我總結(jié)出來(lái)兩點(diǎn):
第一,周末效率有點(diǎn)低下,沒(méi)玩好也沒(méi)學(xué)好,特別容易被打擾,內(nèi)容輸出還是要找一個(gè)安靜、舒適的環(huán)境,這樣精力比較集中;
第二,spring boot真的上頭呀
。感覺(jué)run方法的核心代碼都已經(jīng)分析完了,但我咋發(fā)現(xiàn),我好像還是沒(méi)理清楚spring boot的啟動(dòng)流程呢?或者更準(zhǔn)確的說(shuō)是感覺(jué)目前分析的內(nèi)容和我預(yù)期的是有差異的,而且差異很大,具體的差異感覺(jué)得等我把run方法整體分析完,再回過(guò)頭來(lái)總結(jié),才能得出結(jié)論。現(xiàn)在感覺(jué)好像懂了,但是又沒(méi)完全懂,說(shuō)不懂吧,整體的知識(shí)更清晰了,感覺(jué)還是很朦朧。
確實(shí)有點(diǎn)上頭了,而且spring boot的類名和方法名還老長(zhǎng),經(jīng)常比對(duì)方法名比對(duì)半天……說(shuō)多了都是淚,怕不是有點(diǎn)走火入魔了吧
,趕快結(jié)束吧,后面要慢慢花時(shí)間消化了……
