spring-boot源碼分析之beanFactory · 玖

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

首先它先調用了abstractApplicationContext的onRefresh方法,由于這個是個抽象類,所以實際上調用的是當前容器或者其父類繼承了abstractApplicationContext的類的onRefresh方法,實現onRefresh的類總共有5個:

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

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

createWebContext
這個方法就是為了創(chuàng)建webServer,這一點從名字就可以看出來:

默認情況下webServer和servletContext都是null,所以會創(chuàng)建webServer實例,默認情況下創(chuàng)建的是TomcatWebServer的實例,創(chuàng)建完成后會往beanFactory中注冊webServer的兩個生命周期實例,一個是shutdown,一個是startStop,這兩個生命周期主要是用來控制服務啟停的。

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

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

finishBeanFactoryInitialization
從名字就可以看出來,這個方法就是完成最后的beanFactory初始化,方法注釋也說的很清楚,會初始化剩余的單例bean。
方法主要有四塊內容,第一塊是設置beanFacory的轉換服務,我就說這一塊的代碼咋看著有點眼熟,原來是在分析prepareContext方法的時候,當時也有調用這個方法。
第二塊是注冊已經嵌入的配置值的解析器,這里是lambda的寫法,這注冊的應該是對$Value{name}這樣的配置的解析器
第三塊是獲取加載時間織入器,但是有一點我有點看不懂,getBean是有返回值的,這里也沒有接收,所以這里調用只是為了校驗?

第四塊就是調用beanFactory的三個方法,首先是調用setTempClassLoader置為null,官方給的注釋是停止使用臨時加載器;然后調用freezeConfiguration方法,官方給的注釋是僅獲取bean的定義元數據,不做其他操作;最后調用preInstantiateSingletons方法,從方法名來看這個方法會進行單例bean的預初始化操作,官方給的注釋是實例化剩余的單例。
下面我們詳細看下freezeConfiguration和preInstantiateSingletons,先看freezeConfiguration方法:

本以為這個方法內部實現很復雜,點進來才發(fā)現就兩行代碼,第一行將configurationFronzen設置為true,這個屬性用于標記bean的定義元數據是否已經被緩存。

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

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

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