一文讀懂SpringBoot自動(dòng)裝配原理

SpringBoot 版本 : 2.2.1.RELEASE
關(guān)鍵詞:@EnableAutoConfiguration,/META-INF/spring.factories,
/META-INF/spring-autoconfigure-metadata.properties

注:本文主要講解一些比較重要的關(guān)鍵步驟,不能面面俱到,若有疑問,隨時(shí)保持溝通

  • 大家都知道,SpringBoot 六大特性:
  • 創(chuàng)建獨(dú)立的Spring應(yīng)用
  • 嵌入式Web容器(可以以可執(zhí)行jar方式運(yùn)行,不需要部署WAR文件)
  • 提供固化的 "starter",簡化構(gòu)建配置
  • 當(dāng)條件滿足時(shí)自動(dòng)地裝配Spring或第三方庫
  • 提供運(yùn)維特性(Production-Ready)特性,如指標(biāo)信息(Metrics)、健康檢查、外部化配置。
  • 不需要XML配置
  • 其中有一項(xiàng)為自動(dòng)裝配功能,自動(dòng)裝配功能總體來說由 @EnableXXX注解 + @Import , 再配合@Conditional注解可以實(shí)現(xiàn)條件自動(dòng)裝配,在SpringBoot中核心注解為@EnableAutoConfiguration

1. @EnableAutoConfiguration注解

  • 通常情況下,springBoot應(yīng)用啟動(dòng)類不會(huì)直接標(biāo)注此注解,而是通過@SpringBootApplication注解來實(shí)現(xiàn):
    image.png
    發(fā)現(xiàn) @SpringBootApplication中包含了 @SpringBootConfiguration(等同于@Configuration)、@EnableAutoConfiguration、@ComponentScan 注解。

總結(jié):在啟動(dòng)類上加上 @EnableAutoConfiguration 注解 或者@SpringBootApplication即可實(shí)現(xiàn)自動(dòng)裝配,推薦使用 @SpringBootApplication這個(gè)組合注解。

2. @EnableAutoConfiguration注解實(shí)現(xiàn)自動(dòng)裝配原理

  • 依照 @EnableXXX的驅(qū)動(dòng)設(shè)計(jì),@EnableAutoConfiguration 必然也是按照 @Import 配合 ImportSelector或者 ImportBeandefinetionRegistrar 接口編程的套路,查看@EnableAutoConfiguration注解源碼:
    image.png
    ,果不其然,再進(jìn)一步驗(yàn)證:
    image.png
    ,不知讀者是否還記得作者之前寫過的 SpringBoot啟動(dòng) 源碼深度解析(三)里面會(huì)有@Import注解的詳細(xì)解析過程及 DeferredImportSelector 與 ImportSelector的回調(diào)邏輯。
  • 此時(shí)相信讀者已經(jīng)知道大致的脈絡(luò)了,那么我們就重點(diǎn)分析一下 AutoConfigurationImportSelector 這個(gè) ImportSelector實(shí)現(xiàn)。
  • 正常情況下,若類實(shí)現(xiàn)了 ImportSelector接口,則會(huì)回調(diào)其相對于的 selectImports方法,但是我們通類的關(guān)系圖發(fā)現(xiàn)AutoConfigurationImportSelector 直接實(shí)現(xiàn)的是 DeferredImportSelector,而這個(gè) ImportSelector 如下:
    image.png
    是在Spring 4.0之后新增的延遲ImportSelector,且處理邏輯跟普通的 ImportSelector不同的是當(dāng)前接口新定義了 Group的概念。
    image.png
    追蹤 process方法如下:
    image.png
    image.png
    重點(diǎn)在于此處的 grouping.getImports(),我們發(fā)現(xiàn)是 ConfigurationClassParser的內(nèi)部靜態(tài)類 DeferredImportSelectorGrouping:
    image.png
    ,此類中的兩個(gè)處理方法正正是關(guān)鍵的步驟,而這兩個(gè)方法正是 DeferredImportSelector 中的內(nèi)部接口 Group的實(shí)現(xiàn)去執(zhí)行的。然后我們發(fā)現(xiàn)Group的方法默認(rèn)實(shí)現(xiàn)是AutoConfigurationImportSelector的內(nèi)部靜態(tài)類AutoConfigurationGroup,如下:
    image.png
    ,????看到這里,讀者要是對這些類的名稱記得不是很清晰的話,這一段的說明我建議跟著作者的思路,在本地源碼找到對應(yīng)的位置 "遞歸以上描述",肯定會(huì)恍然大悟,若是熟悉的話可以直接跳過????,然后分析:
  1. getAutoConfigurationMetadata()
image.png
image.png
image.png
  • SprinBoot框架層幫忙做的自動(dòng)裝配元數(shù)據(jù)
  1. AutoConfigurationEntry entry = getAutoConfigurationEntry(autoConfigurationMetadata,annotationMetadata)
image.png
  • AnnotationAttributes attributes = getAttributes(annotationMetadata) 獲取@EnableAutoConfiguration標(biāo)注類的元信息。
  • List<String> configurations = getCandidateConfigurations(annotationMetadata, attributes):由于返回的結(jié)果是候選類的集合,跟蹤調(diào)用鏈會(huì)發(fā)現(xiàn):
    image.png
    image.png

    返回的是 key = org.springframework.boot.autoconfigure.EnableAutoConfiguration對應(yīng)的values值,這些values即是SpringBoot默認(rèn)的自動(dòng)裝配類,所以有時(shí)候讀者閱讀源碼時(shí),發(fā)現(xiàn)某些類莫名其妙的被裝載到Spring容器中了,一部分原因可能是這個(gè)地方搞的鬼。
  1. configurations = removeDuplicates(configurations)
  • 移除重復(fù)定義的配置類( 利用set集合的不可重復(fù)性 )
  1. Set<String> exclusions = getExclusions(annotationMetadata, attributes)
  • 獲取排除類名單,排除類可通過 exclude = {A.class.B.class}屬性來排除指定的配置類。
  1. configurations = filter(configurations, autoConfigurationMetadata)
  • 經(jīng)過去重和排除過的配置類再執(zhí)行過濾操作,過濾代碼:
    image.png
  • ①中 調(diào)用的是 SpringFactoriesLoader.loadFactories(AutoConfigurationImportFilter.class, this.beanClassLoader),也是在spring.factories中獲取 AutoConfigurationImportFilter類型的過濾器,此處默認(rèn)有

    image.png

  • ②中 分別執(zhí)行配置類的match方法,由于 OnBeanCondition、OnClassCondition、OnWebApplicationCondition 均繼承自 FilteringSpringBootCondition,match方法如下:

    image.png
    image.png

  • 通過上面三個(gè)子類的方法實(shí)現(xiàn) ConditionOutcome[] outcomes = getOutcomes(autoConfigurationClasses, autoConfigurationMetadata),此處拿OnBeanCondition類來分析

    image.png
    自動(dòng)裝配類集合迭代調(diào)用 autoConfigurationMetadata.getSet(autoConfigurationClass, "ConditionalOnBean")方法獲取 配置類.ConditionalOnBean的元信息,即在元數(shù)據(jù)配置文件中的 values。
    image.png

    以 RedisCacheConfiguration為例,其 "conditionOnBean" 如下:
    image.png
    ,獲取返回的values值后,再調(diào)用 getOutcome()方法計(jì)算匹配結(jié)果,最終判斷是由
    image.png
    ClassNameFilter.MISSING#matches決定的。

  • 解析到這里,自動(dòng)裝配的底層實(shí)現(xiàn)細(xì)節(jié)基本已經(jīng)說完了,底層實(shí)現(xiàn)稍微有點(diǎn)晦澀難懂,但是只要掌握關(guān)鍵性的類及注解的作用之后,再去了解源碼基本上就可以手到擒來了。

總結(jié):自動(dòng)裝配的流程
  • 添加 @SpringBootApplication 注解或者 @EnableAutoConfiguration
  • 通過 SpringFactoriesLoader.loadFactoryNames(...) 獲取自動(dòng)裝配類,執(zhí)行一系列的去重、排除等操作,然后通過過濾,通過判斷當(dāng)前類加載器是否是加載元數(shù)據(jù)的類加載器來決定 @ConditiionOnXXX 注解的裝配過程。
  • 自動(dòng)裝配是SpringBoot的元數(shù)據(jù)配置文件(spring-autoconfigure-metadata.properties)中的配置類的選擇性加載的過程。
  1. ? 文章要是勘誤或者知識點(diǎn)說的不正確,歡迎評論,畢竟這也是作者通過閱讀源碼獲得的知識,難免會(huì)有疏忽!
  2. ? 要是感覺文章對你有所幫助,不妨點(diǎn)個(gè)關(guān)注,或者移駕看一下作者的其他文集,也都是干活多多哦,文章也在全力更新中。
  3. ? 著作權(quán)歸作者所有。商業(yè)轉(zhuǎn)載請聯(lián)系作者獲得授權(quán),非商業(yè)轉(zhuǎn)載請注明出處!
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。