Spring啓動類源碼學習小記

現在面試Java 的,都必備SpringBoot了,一說SpringBoot,面試官又喜歡問底層,我也是這種形式主義的受害者之一,但是還別說,自從看了底層源碼,心中大致上也有個瞭解,再碰到出問題的時候,解決起來也是比較輕鬆,所以說,雖然增刪改改用不上,但是對於自己未來的發展還是非常有幫助的。
先隨便看一個SpringBoot的啓動類。可以看到最主要的就是一個run方法,理所當然點擊進去看。

在這裏插入圖片描述

繼續點擊進去run

在這裏插入圖片描述

它在這一層new了一個SpringApplication並且又調用run,那就陪着它run進去看看。

在這裏插入圖片描述

在這裏,內容終於開始重要了起來,那些讀取配置信息,做監聽,異常容器初始化,啓動停止的監聽器,讀取自定義banner,打印banner之類的雜七雜八方法不重要,這裏create了一個ApplicationContext,並且有調用了一個refresh() 方法,這個就很重要,容器的初始化和Bean的創建都會在那裏面。點進去refreshContext()方法。

在這裏插入圖片描述

看到了面試官最喜歡問你的refresh()方法本體~

在這裏插入圖片描述

一路refresh()火花帶閃電點進去,看到這裏,就是SpringBoot容器初始化最底層的地塊了。

(1)prepareRefresh()方法:
這是一個創建容器前的刷新預處理方法。執行到這裏,等於宣佈要啓動一個SpringBoot項目了,要動工創建Bean工廠和創建父子容器之類的了
在這裏插入圖片描述
在這裏插入圖片描述
1:initPropertySources():初始化配置和屬性設置,子類自定義個性化的屬性方法等等。

2:校驗屬性的合法性,它會拋出一個什麼“MissingRequiredProperties”的異常,也就是你參數缺失了,或者有錯誤的,都會在這裏拋出來,更詳細的去看這個接口的實現類源碼去背書吧~”
3.earlyApplicationEvents是一個鏈式的HashSet集合類,是用來保存一些初始化早期產生的事件監聽和object的。
(2)obtainFreshBeanFactory:初始化獲取一個BeanFactory
在這裏插入圖片描述
(3)prepareBeanFactory:這個方法就是把上一步創建出來的Beanfactory又傳進去了,傳進去了做一些準備工作和基礎的設置。進去看看~
點進去看發現真的非常的噁心,簡單點總結以下:主要乾了蛇麼:
1:設置BeanFactory的類加載器(setBeanClassLoader),因爲是Bean工廠,怎麼加載類之類的講究,還有表達式解析器。
2:添加一部分後置處理器(addBeanPostProcessor),就是加載一些類之前要做什麼,以怎樣的形式加載,解決一些循環依賴的問題。
3:設置忽略的自動裝配的接口(ignoreDependency),忽略一些不必要的。
4:註冊可以解析的自動裝配(registerResolvableDependency),這樣就可以在任何組件中自動注入Bean,例如在BeanFactory中,ApplicationContext中,ResourceLoader中等等。
5:添加後置處理器(BeanPostProcessor)。
6:添加編譯時的AspectJ,代理模式的切面。這個切面在初始化和後置處理器中也是經常使用,通常是循環執行完一堆前置方法,纔到目標方法,又執行一堆的後置方法,超級囉嗦,看得很乏困。
7:給BeanFactory註冊Environment,SystemPropertiew等等一些用到的組件。
在這裏插入圖片描述
(4)postProcessBeanFactory:Bean工廠做完了準備工作後進行後置處理工作在這裏插入圖片描述
子類可以通過重寫這個方法,實現在初始化創建BeanFactory完成後做一些自己進一步的Diy設置。
(5)invokeBeanFactoryPostProcessors,registerBeanPostProcessors:這兩個方法很囉嗦,就是一堆後置處理器,先執行BeanDefinitionRegistry定義的方法,通過優先級先後執行註冊,也就是把BeanPostProcessor添加到bean工廠中,其中有個Ordered順序接口規定了先執行哪些,再執行哪些方法,執行完有序有優先級的,再執行無需無優先級的BeanDefinitionRegistryPostProcessors…這裏給我的感覺,就像是剝洋蔥一樣,一層層的剝開,看了一眼洋蔥的心後,又一層一層包裹起來。
不剝開外面那層,別想着到裏面那層的方法。在這裏插入圖片描述
(6)initMessageSource:這個其實是通過MessageSource組件實現消息綁定,消息解析的國際化功能,通過國際化配置文件的key對應的value,按照區域信息獲取,並且把獲取到的信息創建好一個MessageSource放入BeanFactory中,再要用到國際化配置文件的值時候就可以自動注入了。
在這裏插入圖片描述
(7)初始化事件派發器,並且將ApplicationEventMulticaster添加到BeanFactory中,方便自動注入。
在這裏插入圖片描述
(8)registerListeners:用迭代器模式將所有ApplicationListener註冊到事件派發器中。
ApplicationListener是事件監聽ApplicationEvent的,是ApplicationContext事件機制中的一環節。通過它可以監聽對應事件發生,從而進行某種自定義的操作。
在這裏插入圖片描述
(9)finishBeanFactoryInitialization:初始化剩下的所有單實例Bean。獲取容器中所有的Bean進行初始化和創建對象。首先獲取定義信息,RootBeanDefinition,通過懶加載,單實例的方式。
判斷是否工廠Bean,是否實現工廠Bean接口的Bean,如果都不是,就去緩存中找是否已經有該Bean存在,沒有的話,調用工廠模式著名的getBean(beanName);反射機制進行創建對象,創建前又會獲取當前Bean是否依賴其他的Bean,如果有,就先getBean(beanName)先創建依賴的Bean,再創建目標Bean,再放回緩存中,再標誌一下當前Bean已經被創建。
這裏又會有一堆的BeanPostProcessorsAfterInitialIzation,顧名思義初始化前要做的事情,初始化後要做的又是一堆事情。判斷是否自定義初始化方法,註冊Bean的銷燬方法,創建出來後把Bean放在單實例Bean緩存中(singletonObject)。
這麼一通折騰下來,就算是初始化好了,這就是我們看到的banner圖打印,跟着一大堆log,然後初始化一堆的Bean放入BeanFactory,然後假如沒加註解,但是又在另外一個地方@Autowired或者@Resource的話,SpringBoot就找不到對應的依賴Bean放入IOC容器中,這裏說的容器,其實就都是Map,通過Key(類名,全限定類名)Value(單例模式創建好的Bean存放在內存的地址,對象類型,存的是引用)。

以上是我個人學習後的總結,如果有說錯的地方希望一起討論哈~
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章