0
  • 聊天消息
  • 系統(tǒng)消息
  • 評論與回復
登錄后你可以
  • 下載海量資料
  • 學習在線課程
  • 觀看技術視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會員中心
創(chuàng)作中心

完善資料讓更多小伙伴認識你,還能領取20積分哦,立即完善>

3天內(nèi)不再提示

初學者必看的SpringBoo自動裝配原理4

jf_78858299 ? 來源:CSDN CC_且聽風吟 ? 作者:CC_且聽風吟 ? 2023-04-07 11:03 ? 次閱讀

7. 自動裝配源碼分析

終于來到了大家喜聞樂見的部分:源碼分析

在我們前面6節(jié)學習了各種”招式“之后,讓我們請出對手:SpringBoot

現(xiàn)在在你面前的是一個SpringBoot”空項目“,沒有添加任何依賴包和starter包

啟動項目:

正常啟動,讓我們從@SpringBootApplication開始研究

7.1 @SpringBootConfiguration

會看到@SpringBootApplication這個注解由好多注解組成

主要的有以下三個:

@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan

先來看第一個:@SpringBootConfiguration

進入這個注解之后會發(fā)現(xiàn)

原來你就是一個@Configuration啊,一個JavaConfig配置類

那我們使用JavaConfig不就是用來配置bean嗎,所以有了這個注解之后我們可以在SpringBoot運行的主類中使用@Bean標簽配置類了,如下圖所示:

7.2 @ComponentScan

這個注解相信大家都認識了,組件掃描

這個掃描的范圍是:SpringBoot主啟動類的同級路徑及子路徑

7.3 @EnableAutoConfiguration

來看這個注解,也是最核心的內(nèi)容

這個注解怎么這么眼熟啊,還記得剛才的@MyEnableAutoConfig注解嗎?就是我們自己寫的那個注解

進入@EnableAutoConfiguration:

看圖中紅圈位置的注解:@Import(AutoConfigurationImportSelector.class)

是不是跟我們上面自己寫的內(nèi)容一樣!

這里的作用便是導入了 AutoConfigurationImportSelector 這個類的bean定義

我們都知道,如果這個類實現(xiàn)了ImportSelector接口,那他肯定重寫了一個方法,就是我們上面重寫過的selectImports方法:

果然,在這個類里面確實有這個selectImports方法:

我的天,好長的一串代碼,一行都放不下!

此時此刻,我又回想起了在家鄉(xiāng)的母親,夏天的蟬鳴,池塘的荷花…

等等等等,這個類我們當時返回的是什么?是一個字符串數(shù)組String[ ],那這個類無論多么長,返回的肯定就是一個字符串數(shù)組,不信你自己看:

這個字符串數(shù)組存放的內(nèi)容我們是否清楚呢?當然清楚了!我們返回的是要加載的Config配置文件的全包名,通過返回這個全包名,我們就能自動裝配上這些配置文件下定義的bean對象,從而達到了自動裝配的目的!

根據(jù)剛才我們自己實現(xiàn)的selectImports方法,我們是通過注解類的名字來查找,并且最終得到需要加載的Config類的全類名,最后返回的。

因此,這里必然有一個根據(jù)注解類名字來查找相應的Config文件的操作

我們繼續(xù)反推,看到返回時的定義如下:

我們發(fā)現(xiàn)autoConfigurationEntry中保存著我們需要的配置信息,它是通過getAutoConfigurationEntry方法獲取的,于是我們繼續(xù)深入,進入getAutoConfigurationEntry方法

這一段代碼真是把人難住了,好大一片,不知道在做什么

此時此刻,我又回想起了在家鄉(xiāng)的母親,夏天的蟬鳴,池塘的荷花…

回家!有了!我們先想這個方法應該返回什么,根據(jù)我們前面的經(jīng)驗,這里應該返回一個類似于Entry的保存了我們需要的配置信息的對象

這個方法返回的是新建的AutoConfigurationEntry對象,根據(jù)最后一行的構(gòu)造函數(shù)來看,給他了兩個參數(shù)

configurations, exclusions

configurations顯然使我們需要的配置文件,也是我們最關心的,而exclusions字面意思是排除,也就是不需要的,那我們接下來應該關注configurations到底是怎么來的

根據(jù)我們前面的經(jīng)驗,我們是根據(jù)注解類名來從一個配置文件中讀取出我們需要的Config配置類,這里configurations就代表了Config配置類,那么我們應該找到一個入口,這個入口跟注解相關,并且返回了configurations這個參數(shù)。

正如我們所料,這個方法的參數(shù)確實傳遞過來了一個東西,跟注解有關:

看見那個大大的Annotation(注解)了嗎!

那么根據(jù)這條”線索“,我們按圖索驥,找到了三行代碼,范圍進一步縮小了!

此時再加上返回了configurations,我們最終確定了一行代碼:

就是這個getCandidateConfigurations方法,符合我們的要求!

從字面意思上分析,獲取候選的配置,確實是我們需要的方法

OK,讓我們繼續(xù)前進,進入這個方法:

這個方法是不是也似曾相識呢?我們之前寫過一個專門用于讀取配置文件的類MyPropertyReader,還記得嗎?

如果你還記得的話,我們自己寫的工具類里面也是一個靜態(tài)方法readPropertyForMe來幫我讀取配置文件

但是我們的配置文件路徑一定是需要指定的,不能亂放。

從這個loadFactoryNames方法體來看,好像沒有給他傳遞一個具體路徑

但是從下面的Assert斷言中,我們發(fā)現(xiàn)了玄機:

在META-INF/spring.factories文件中沒有找到自動配置類Config,你要檢查balabala。。。。

根據(jù)我不太靈光的腦袋的判斷,他的這個配置文件就叫spring.factories,存放的路徑是META-INF/spring.factories

于是我們打開spring boot自動裝配的依賴jar包:

那這個配置文件里面的內(nèi)容,是不是跟我們想的一樣呢?

原來如此。

這里的EnableAutoConfiguration注解,正是我們此行的起點啊…

到這里,自動裝配到底是什么,應該比較清楚了,原來他是幫我們加載了各種已經(jīng)寫好的Config類文件,實現(xiàn)了這些JavaConfig配置文件的重復利用和組件化

7.4 loadFactoryNames方法

行程不能到此結(jié)束,學習不能淺嘗輒止。

我們還有最后一塊(幾塊)面紗沒有解開,現(xiàn)在還不能善罷甘休。

讓我們進入loadFactoryNames方法:

這個方法非常簡短,因為他調(diào)用了真正實現(xiàn)的方法:loadSpringFactories

這一行return代碼我復制在下面:

loadSpringFactories(classLoader)
     .getOrDefault(factoryTypeName, Collections.emptyList());

可以分析得出:loadSpringFactories方法的返回值又調(diào)用了一個getOrDefault方法,這明顯是一個容器類的方法,目的是從容器中拿點東西出來

就此推測:loadSpringFactories返回了一個包含我們需要的Config全類名(字符串)的集合容器,然后從這個集合容器中拿出來的東西就是我們的configurations

讓我們看這個loadSpringFactories方法:

它確實返回了一個容器:Map 這個容器的類型是:MultiValueMap

這個數(shù)據(jù)結(jié)構(gòu)就非常牛逼了,多值集合映射(我自己的翻譯)簡單來說,一個key可以對應多個value,根據(jù)他的返回值,我們可以看到在這個方法中一個String對應了一個List

那么不難想到MultiValueMap中存放的形式:是”注解的類名——多個Config配置類“ 讓我們打個斷點來驗證一下:

果然是這樣,并且@EnableAutoConfiguration注解竟然加載了多達124個配置類!

接下來我們繼續(xù)思考:我們來的目的是獲取configurations,所以無論你做什么,必須得讀取配置文件,拿到configurations

于是我們在try方法體中果然發(fā)現(xiàn)了這個操作:

他獲取了一個路徑urls,那么這個路徑是否就是我們前面驗證的META-INF/spring.factories呢?

我們查看靜態(tài)常量FACTORIES_RESOURCE_LOCATION的值:

果真如此,bingo!繼續(xù)往下看,果然他遍歷了urls中的內(nèi)容,從這個路徑加載了配置文件:終于看到了我們熟悉的loadProperties方法!

那我們大概就知道了,他確實是通過找到路徑,然后根據(jù)路徑讀取了配置文件,然后返回了讀取的result

這就是loadFactoryNames方法的內(nèi)部實現(xiàn)。

7.5 cache探秘

到這里有的人又要問了:是不是結(jié)束了?其實還遠沒有!

細心地朋友已經(jīng)發(fā)現(xiàn)了玄機,隱藏在loadFactoryNames方法的開頭和結(jié)尾:

喂喂,這個返回的result好像并不是直接new出來的哦

它是從cache緩存中取出來的,你發(fā)現(xiàn)了沒有

根據(jù)下面的if判斷,如果從緩存中讀取出來了result,并且result的結(jié)果不為空,就直接返回,不需要再進行下面的讀寫操作了,這樣減少了磁盤頻繁的讀寫I/O

同理,在我更新完所有的配置文件資源之后,退出時也要更新緩存。

7.6 getAutoConfigurationEntry再探

關鍵部分已經(jīng)過去,讓我們反過頭來重新審視一下遺漏的內(nèi)容:

還記得getAutoConfigurationEntry方法嗎?

我們最后來研究一下這個類除了getCandidateConfigurations還干了哪些事情:

  • removeDuplicates
  • configurations.removeAll(exclusions)

可以看到,這里對加載進來的配置進行了去重、排除的操作,這是為了使得用戶自定義的排除包生效,同時避免包沖突異常,在SpringBoot的入口函數(shù)中我們可以通過注解指定需要排除哪些不用的包:

例如我不使用RabbitMQ的配置包,就把它的配置類的class傳給exclude

@SpringBootApplication(exclude = {RabbitAutoConfiguration.class})

8. 自動裝配本質(zhì)

我的理解:

  • SpringBoot自動裝配的本質(zhì)就是通過Spring去讀取META-INF/spring.factories中保存的配置類文件然后加載bean定義的過程。
  • 如果是標了@Configuration注解,就是批量加載了里面的bean定義
  • 如何實現(xiàn)”自動“:通過配置文件獲取對應的批量配置類,然后通過配置類批量加載bean定義,只要有寫好的配置文件spring.factories就實現(xiàn)了自動。

9. 總結(jié)

Spring Boot的自動裝配特性可以說是Spring Boot最重要、最核心的一環(huán),正是因為這個特性,使得我們的生產(chǎn)復雜性大大降低,極大地簡化了開發(fā)流程,可以說是給我們帶來了巨大的福音了~~

筆者本人對源碼的理解仍然沒有那么深刻,只是喜歡分享自己的一些學習經(jīng)驗,希望能和大家共同學習,畢竟掌握一門新技術的快感嘛… 大家都懂的!

寫這篇文章耗費了巨大的精力,每一個字均是手碼,真的希望喜歡的朋友可以點贊收藏關注支持一波,這就是對我這個未出世的學生的最大激勵了!

聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權轉(zhuǎn)載。文章觀點僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場。文章及其配圖僅供工程師學習之用,如有內(nèi)容侵權或者其他違規(guī)問題,請聯(lián)系本站處理。 舉報投訴
  • spring
    +關注

    關注

    0

    文章

    340

    瀏覽量

    14344
  • 源碼分析
    +關注

    關注

    0

    文章

    5

    瀏覽量

    5552
  • 自動裝配
    +關注

    關注

    0

    文章

    7

    瀏覽量

    653
收藏 人收藏

    評論

    相關推薦

    protel技術大全--初學者必看

    protel技術大全--初學者必看。
    發(fā)表于 08-04 10:36

    PSOC1初學者必看的10個實例

    PSOC1初學者必看的10個實例
    發(fā)表于 11-19 16:33

    MATLAB入門教程-初學者必看

    MATLAB入門教程-初學者必看
    發(fā)表于 06-28 15:39

    Linux初學者必看?。?!

    Linux初學者必看?。?!
    發(fā)表于 01-07 21:35

    單片機入門秘籍,初學者必看

    初學者必看的單片機秘籍
    發(fā)表于 04-29 16:10

    PCB LAYOUT初學者必看!

    PCBLAYOUT技術大全---初學者必看! PROTEL相關疑問 1.原理圖常見錯誤: (1)ERC報告管腳沒有接入信號: a.創(chuàng)建封裝時給管腳定義了I/O屬性; b.創(chuàng)建元件或放置元件時修改了不一致的grid屬性
    發(fā)表于 09-13 15:23 ?0次下載

    PSOC1初學者5個實驗,針對初學者的實驗

    PSOC1初學者5個實驗,針對初學者的實驗
    發(fā)表于 10-16 09:33 ?14次下載
    PSOC1<b class='flag-5'>初學者</b>5個實驗,針對<b class='flag-5'>初學者</b>的實驗

    初學者必看的基本電子技術概念

    初學者必看的基本電子技術概念
    發(fā)表于 05-17 11:41 ?0次下載

    初學者必看的電源測試項目要點及教程

    初學者必看的電源測試項目要點及教程
    發(fā)表于 07-01 14:09 ?29次下載

    初學者必看的LABVIEW工程師編程經(jīng)驗

    初學者必看的LABVIEW工程師編程經(jīng)驗
    發(fā)表于 07-12 14:24 ?29次下載

    ARM與嵌入式linux入門的建議(初學者必看)

    ARM與嵌入式linux入門的建議(初學者必看)(嵌入式開發(fā)培訓怎么樣)-該文檔為ARM與嵌入式linux入門的建議(初學者必看)總結(jié)文檔,是一份很不錯的參考資料,具有較高參考價值,感
    發(fā)表于 08-04 10:02 ?15次下載
    ARM與嵌入式linux入門的建議(<b class='flag-5'>初學者</b><b class='flag-5'>必看</b>)

    初學者必看的單片機程序匯總

    初學者必看的單片機程序匯總
    發(fā)表于 09-15 14:33 ?49次下載

    初學者必看SpringBoo自動裝配原理1

    學習SpringBoot,絕對避不開自動裝配這個概念,這也是SpringBoot的關鍵之一 本人也是SpringBoot的初學者,下面的一些總結(jié)都是結(jié)合個人理解和實踐得出的,如果有錯誤或者疏漏,請一定一定一定(不是歡迎,是
    的頭像 發(fā)表于 04-07 11:03 ?642次閱讀
    <b class='flag-5'>初學者</b><b class='flag-5'>必看</b>的<b class='flag-5'>SpringBoo</b><b class='flag-5'>自動</b><b class='flag-5'>裝配</b>原理1

    初學者必看SpringBoo自動裝配原理2

    學習SpringBoot,絕對避不開自動裝配這個概念,這也是SpringBoot的關鍵之一 本人也是SpringBoot的初學者,下面的一些總結(jié)都是結(jié)合個人理解和實踐得出的,如果有錯誤或者疏漏,請一定一定一定(不是歡迎,是
    的頭像 發(fā)表于 04-07 11:03 ?568次閱讀

    初學者必看SpringBoo自動裝配原理3

    學習SpringBoot,絕對避不開自動裝配這個概念,這也是SpringBoot的關鍵之一 本人也是SpringBoot的初學者,下面的一些總結(jié)都是結(jié)合個人理解和實踐得出的,如果有錯誤或者疏漏,請一定一定一定(不是歡迎,是
    的頭像 發(fā)表于 04-07 11:03 ?569次閱讀
    <b class='flag-5'>初學者</b><b class='flag-5'>必看</b>的<b class='flag-5'>SpringBoo</b><b class='flag-5'>自動</b><b class='flag-5'>裝配</b>原理3