21-Spring高級容器初始化:初始化非延遲加載單例bean

開篇
上一節(jié),我們了解了在Spring中是如何基于事件驅(qū)動開發(fā)的,其實就是將監(jiān)聽器注冊到事件廣播器中,然后當Spring發(fā)布事件時,事件廣播器會遍歷所有注冊的監(jiān)聽器,并通過監(jiān)聽該事件的監(jiān)聽器來處理事件。
這一節(jié),我們主要來了解下一下ApplicationContext初始化過程中最后的一些邏輯,主要包括以下幾個部分:
1.看下ApplicationContext是如何注冊監(jiān)聽器的
2.看下ApplicationContext是如何初始化非延遲加載單例的
3.最后來看下ApplicationContext是如何開啟Spring的生命周期的
注冊監(jiān)聽器ApplicationListener
接下來,我們繼續(xù)回到refresh方法中來:

可以看到,在前面的方法initApplicationEventMulticaster分析完之后,我們接著再到方法onRefresh中看下:

可以看到方法onRefresh也是一個空實現(xiàn)方法,和之前很多的空實現(xiàn)方法一樣,方法onRefresh也是由關鍵字protected修飾的,也就是說方法onRefresh也是Spring留給子類的一個擴展方法。
我們繼續(xù)往后面看:

可以看到,通過方法registerListeners的名稱,我們大概可以知道應該是要注冊一些監(jiān)聽器了,那具體是如何注冊的呢?可以到方法registerListeners里面看下:

可以看到,在方法registerListeners中也沒有什么特別的東西,比較關鍵的無非也就是將參數(shù)中的監(jiān)聽器以及從Spring容器中獲取到的監(jiān)聽器,分別都注冊到廣播器中。
從這里我們可以知道在上一節(jié)的內(nèi)容中,為什么我們可以從廣播器中獲取到監(jiān)聽器了。
初始化非延遲加載的單例
其實分析到這里,ApplicationContext的初始化環(huán)節(jié)已經(jīng)差不多快結(jié)束了,我們把后面一些收尾的地方來看下,再次回到refresh方法:

跟進到方法finishBeanFactoryInitialization中看下:

可以看到,在finishBeanFactoryInitialization方法中,其實就是初始化了一些比較瑣碎的東西,我們重點來看下beanFactory調(diào)用的方法preInstantiateSingletons:

可以看到,在方法preInstantiateSingletons中,首先會遍歷所有注冊到Spring容器中的BeanDefinition,如果BeanDefinition的屬性scope的值為singleton也就是單例的,同時屬性lazyInit的值為false,說明該BeanDefinition對應的bean是不允許懶加載的單例。
既然bean不允許懶加載,那當然就要立馬去加載它了,所以,我們可以看到接下來就會調(diào)用getBean方法去實例化bean了,又因為bean的屬性scope值為singleton,也就是bean是單例的,所以,Spring會把實例化好的bean放一份到單例緩存中。
這樣的話,當Spring下一次要用到bean的實例時,就可以直接從單例緩存中獲取bean的實例了,默認情況下配置的bean都是不會在Spring容器初始化時加載的。
但是,如果你希望自己配置的bean不要懶加載,而是在Spring容器初始化時就率先去加載它,那你完全可以為這個bean配置屬性lazyInit的值為false,就像這樣:
<bean?id="student"?class="com.ruyuan.container.Student"?lazy-init="false"/>
開啟Spring的生命周期
最后,refresh方法中還剩最后一塊邏輯,我們來看下:

我們跟進到finishRefresh方法中看下:

可以看到finishRefresh方法中其實也就沒有太多東西了,主要初始化和生命周期相關的一些組件,我們可以先到initLifecycleProcessor方法,看下做了哪些事情:

可以看到,在方法initLifecycleProcessor中,首先就是到Spring容器中看下是否存在名稱為lifecycleProcessor的bean。
如果存在的話,直接從Spring容器中獲取出來,并賦值給成員變量lifecycleProcessor,如果不存在的話默認會創(chuàng)建一個DefaultLifecycleProcessor類型的對象,并賦值給成員變量lifecycleProcessor,最后再注入到Spring容器中,那DefaultLifecycleProcessor又是什么呢?
其實DefaultLifecycleProcessor是Spring中,處理Spring生命周期相關的一個組件,Spring提供生命周期的接口Lifecycle,這塊我們可以結(jié)合DefaultLifecycleProcessor的類繼承圖看下:

可以看到,DefaultLifecycleProcessor最終也是實現(xiàn)接口Lifecycle的,而LifecycleProcessor接口也只不過是Lifecycle接口的一個擴展接口而已,我們可以看下這兩個接口中的方法:

在Spring中如果bean實現(xiàn)了接口Lifecycle,Spring會保證在容器啟動時,就會調(diào)用這些bean中的start方法開啟它們的生命周期,當然,在Spring關閉的時候也會調(diào)用stop方法來結(jié)束它們的生命周期。
而LifecycleProcessor在Lifecycle的基礎上,又添加了兩個方法onRefresh和onClose,主要就是對相應的bean做狀態(tài)更新,關于onRefresh方法的邏輯,我們可以來看下:

可以看到,接下來會調(diào)用LifecycleProcessor中的onRefresh方法,我們到onRefresh方法中看下:


可以看到在onRefresh方法中,像我們剛才分析的一樣,就會從Spring容器中獲取所有實現(xiàn)了Lifecycle接口的bean,然后調(diào)用start方法來開啟它們的生命周期,也就是開啟Spring的生命周期了。
最后,方法finishRefresh的一些邏輯我們也來看下:

可以看到,其實就是發(fā)布了一個刷新上下文的事件ContextRefreshedEvent。
根據(jù)我們前面的源碼分析,事件ContextRefreshedEvent將會注冊到廣播器中,廣播器會把該事件廣播器相應的監(jiān)聽器去處理,這個事件相當于告訴Spring整個容器已經(jīng)刷新了,也就說Spring容器ApplicationContext已經(jīng)初始化完畢了。
總結(jié)
這一節(jié),主要有以下幾個重要的點:
通過一張圖來梳理下這兩節(jié)課的內(nèi)容:

上一節(jié),我們看到了ApplicationContext初始化了消息源以及事件廣播器,而且通過一個案例我們對廣播器如何結(jié)合監(jiān)聽器以及事件的使用,也有了一定的認識了。
這一節(jié),我們陸續(xù)又了解了Spring是如何注冊監(jiān)聽器的,同時是如何初始化非延遲加載的單例bean,相當于在Spring容器初始化環(huán)節(jié)就預先加載這些bean了,這樣在使用這些bean的時候,我們可以盡早獲取到這些bean的實例。
當所有東西都初始化好之后,Spring容器也就初始化完成了,這個時候Spring會初始化生命周期組件LifecycleProcessor,并且通過onRefresh方法,對那些實現(xiàn)了Lifecycle接口的bean開啟生命周期,最后并發(fā)布一個事件,通知Spring容器刷新即容器初始化這件事已經(jīng)完成了。