1. 程式人生 > >品Spring:SpringBoot輕鬆取勝bean定義註冊的“第一階段”

品Spring:SpringBoot輕鬆取勝bean定義註冊的“第一階段”

上一篇文章強調了bean定義註冊佔Spring應用的半壁江山。而且詳細介紹了兩個重量級的註冊bean定義的類。

今天就以SpringBoot為例,來看看整個SpringBoot應用的bean定義是如何註冊進容器的。

先來看看經典的啟動入口,如下圖01:


可以看到呼叫的是run方法,並把主類(main或primary)作為第一個引數出入。

接下來要做的事情,就是順藤摸瓜,看看到底發生了什麼,並確定下究竟哪些類被註冊了bean定義。

此時,我就是一個快樂的小偵探,OK,走起。

上面的呼叫走到了這裡,如下圖02:


可以看到把第一個引數(即主類)放入數組裡,又呼叫了一個run方法,如下圖03:


使用第一個引數(即主類)去呼叫了建構函式,得到了例項物件,然後又呼叫了例項的run方法。

順著建構函式走下去,最終走到了這裡,如圖04:


發現最終主類被,放到Set<Class<?>>型別的primarySources欄位中。

程式設計新說注:通過搜尋全類,發現這個欄位除了剛剛放入的主類外,再沒有放入其它類。

接著再沿著run方法往下走,來到了這裡,如下圖05:


首先定義了一個容器類的變數,然後建立容器類的例項,就是通過反射呼叫構造函數了。

然後就是準備容器,進入方法裡看看,如下圖06:


在方法最後終於看到了我們期望的,即bean定義的註冊。

發現要註冊的資源是getAllSources()這個方法返回的,那就進去看看吧,如下圖07:



看到資源來自於primarySources欄位和sources欄位。第一個欄位上文已經講了,只包含主類。

程式設計新說注:通過搜尋全類,發現第二個欄位sources是null,因此它不包含資源。

因此,真正獲取到的用於註冊bean定義的資源只有主類自己。

那就打破砂鍋走到底,繼續吧。

再來看看load方法,如下圖08:


使用剛剛獲取到的資源建立了BeanDefinitionLoader類的例項。

這個類是SpringBoot定義的,類似於一個門面,因為它包含了所有註冊bean定義的方式。

這個類就是最後一步了,因此來看看,如下圖09:


首先是一個Object[]型別(之所以用Object,是因為資源型別有多種)的sources欄位,用於儲存剛剛獲取的資源。


剩下四個都是用來註冊bean定義的,其中兩個上一篇已經講過。剩餘兩個是處理xml和groovy的,一個已經過時,一個尚未流行。


最後再來看一眼,生成例項時呼叫的建構函式,如下圖10:


就是對五個欄位的賦值或例項化,並無特別之處。(其實是有的,先賣個關子)

接下來就是根據資源的具體型別,使用四個bean定義註冊類中的一個來註冊bean定義。

這一通分析下來,推匯出來的結論是:

截止到目前,只有主類自己被註冊了bean定義。

為了證明這一點,把日誌級別改為DEBUG,如下圖11:


可以看出在原始碼中,把資源陣列進行了debug輸出。

最終輸出內容,如下圖12:


發現確實只註冊了主類自己,沒有其它。和我們分析的一樣,哈哈。

到現在prepareContext已經執行完畢了,接下來該執行的就是refreshContext了。

熟悉Spring容器的都知道,refresh其實就是容器的啟動了。

因此最後得出一個結論,對於“常規”的SpringBoot應用:

在Spring容器啟動前,只有應用的主類自己被註冊了bean定義。

What,are you kidding me?

Of course not。

那其它的那些bean定義是何時及如何註冊的呢?

且聽下回分解。

最後來看看主類的bean定義資訊,作為一個小小的彩蛋吧。

如下圖13:


可以看出bean名稱符合生成規則,bean定義使用了CGLIB生成了代理。

bean的一些屬性,單例、非抽象、非延遲載入、未明確定義自動裝配方式、作為自動裝配候選bean,非主要的等等。

bean定義的實現類是AnnotatedGenericBeanDefinition,可知是通過程式設計方式(而非jar包掃描)註冊的bean定義。

預祝,看過本文的人都有所收穫。若能轉發一下,則求之不得。

 

>>> 品Spring系列文章 <<<

 

品Spring:帝國的基石

品Spring:bean定義上梁山

品Spring:實現bean定義時採用的“先進生產力”

品Spring:註解終於“成功上位”

品Spring:能工巧匠們對註解的“加持”

品Spring:SpringBoot和Spring到底有沒有本質的不同?

品Spring:負責bean定義註冊的兩個“排頭兵”

 

作者是工作超過10年的碼農,現在任架構師。喜歡研究技術,崇尚簡單快樂。追求以通俗易懂的語言解說技術,希望所有的讀者都能看懂並記住。下面是公眾號和知識星球的二維碼,歡迎關注!