天天看點

SpringBoot自動裝配 源碼解析

SpringBoot 版本 : 2.2.1.RELEASE

關鍵詞:@EnableAutoConfiguration,/META-INF/spring.factories,/META-INF/spring-autoconfigure-metadata.properties

注:本文主要講解一些比較重要的關鍵步驟,不能面面俱到,若有疑問,随時保持溝通

大家都知道,SpringBoot 六大特性:

  • 建立獨立的Spring應用
  • 嵌入式Web容器(可以以可執行jar方式運作,不需要部署WAR檔案)
  • 提供固化的 "starter",簡化建構配置
  • 當條件滿足時自動地裝配Spring或第三方庫
  • 提供運維特性(Production-Ready)特性,如名額資訊(Metrics)、健康檢查、外部化配置。
  • 不需要XML配置
  • 其中有一項為自動裝配功能,自動裝配功能總體來說由 @EnableXXX注解 + @Import , 再配合@Conditional注解可以實作條件自動裝配,在SpringBoot中核心注解為@EnableAutoConfiguration

1. @EnableAutoConfiguration注解

  • 通常情況下,springBoot應用啟動類不會直接标注此注解,而是通過@SpringBootApplication注解來實作:發現 @SpringBootApplication中包含了 @SpringBootConfiguration(等同于@Configuration)、@EnableAutoConfiguration、@ComponentScan 注解。
總結:在啟動類上加上 @EnableAutoConfiguration 注解 或者@SpringBootApplication即可實作自動裝配,推薦使用 @SpringBootApplication這個組合注解。

2. @EnableAutoConfiguration注解實作自動裝配原理

  • 依照 @EnableXXX的驅動設計,@EnableAutoConfiguration 必然也是按照 @Import 配合 ImportSelector或者 ImportBeandefinetionRegistrar 接口程式設計的套路,檢視@EnableAutoConfiguration注解源碼:,果不其然,再進一步驗證:,不知讀者是否還記得作者之前寫過的 SpringBoot啟動 源碼深度解析(三) ,裡面會有@Import注解的詳細解析過程及 DeferredImportSelector 與 ImportSelector的回調邏輯。
  • 此時相信讀者已經知道大緻的脈絡了,那麼我們就重點分析一下 AutoConfigurationImportSelector 這個 ImportSelector實作。
  • 正常情況下,若類實作了 ImportSelector接口,則會回調其相對于的 selectImports方法,但是我們通類的關系圖發現AutoConfigurationImportSelector 直接實作的是 DeferredImportSelector,而這個 ImportSelector 如下: 是在Spring 4.0之後新增的延遲ImportSelector,且處理邏輯跟普通的 ImportSelector不同的是目前接口新定義了 Group的概念。 追蹤 process方法如下:重點在于此處的 grouping.getImports(),我們發現是 ConfigurationClassParser的内部靜态類 DeferredImportSelectorGrouping: ,此類中的兩個處理方法正正是關鍵的步驟,而這兩個方法正是 DeferredImportSelector 中的内部接口 Group的實作去執行的。然後我們發現Group的方法預設實作是AutoConfigurationImportSelector的内部靜态類AutoConfigurationGroup,如下:,👍👍看到這裡,讀者要是對這些類的名稱記得不是很清晰的話,這一段的說明我建議跟着作者的思路,在本地源碼找到對應的位置

    "遞歸以上描述"

    ,肯定會恍然大悟,若是熟悉的話可以直接跳過👍👍,然後分析:
  1. getAutoConfigurationMetadata()
  • SprinBoot架構層幫忙做的自動裝配中繼資料
  1. AutoConfigurationEntry entry = getAutoConfigurationEntry(autoConfigurationMetadata,annotationMetadata)
  • AnnotationAttributes attributes = getAttributes(annotationMetadata) 擷取@EnableAutoConfiguration标注類的元資訊。
  • List configurations = getCandidateConfigurations(annotationMetadata, attributes):由于傳回的結果是候選類的集合,跟蹤調用鍊會發現:

    傳回的是 key = org.springframework.boot.autoconfigure.EnableAutoConfiguration對應的values值,這些values即是SpringBoot預設的自動裝配類,是以有時候讀者閱讀源碼時,發現某些類莫名其妙的被裝載到Spring容器中了,一部分原因可能是這個地方搞的鬼。

  1. configurations = removeDuplicates(configurations)
  • 移除重複定義的配置類( 利用set集合的不可重複性 )
  1. Set exclusions = getExclusions(annotationMetadata, attributes)
  • 擷取排除類名單,排除類可通過 exclude = {A.class.B.class}屬性來排除指定的配置類。
  1. configurations = filter(configurations, autoConfigurationMetadata)
  • 經過去重和排除過的配置類再執行過濾操作,過濾代碼:
  • ①中 調用的是 SpringFactoriesLoader.loadFactories(AutoConfigurationImportFilter.class, this.beanClassLoader),也是在spring.factories中擷取 AutoConfigurationImportFilter類型的過濾器,此處預設有
  • ②中 分别執行配置類的match方法,由于 OnBeanCondition、OnClassCondition、OnWebApplicationCondition 均繼承自 FilteringSpringBootCondition,match方法如下:
  • 通過上面三個子類的方法實作 ConditionOutcome[] outcomes = getOutcomes(autoConfigurationClasses, autoConfigurationMetadata),此處拿OnBeanCondition類來分析:自動裝配類集合疊代調用 autoConfigurationMetadata.getSet(autoConfigurationClass, "ConditionalOnBean")方法擷取

    配置類.ConditionalOnBean

    的元資訊,即在中繼資料配置檔案中的 values。

    以 RedisCacheConfiguration為例,其 "conditionOnBean" 如下:,擷取傳回的values值後,再調用 getOutcome()方法計算比對結果,最終判斷是由 ClassNameFilter.MISSING#matches決定的。

  • 解析到這裡,自動裝配的底層實作細節基本已經說完了,底層實作稍微有點晦澀難懂,但是隻要掌握關鍵性的類及注解的作用之後,再去了解源碼基本上就可以手到擒來了。
總結:自動裝配的流程
  • 添加 @SpringBootApplication 注解或者 @EnableAutoConfiguration
  • 通過 SpringFactoriesLoader.loadFactoryNames(...) 擷取自動裝配類,執行一系列的去重、排除等操作,然後通過過濾,通過判斷目前類加載器是否是加載中繼資料的類加載器來決定 @ConditiionOnXXX 注解的裝配過程。
  • 自動裝配是SpringBoot的中繼資料配置檔案(spring-autoconfigure-metadata.properties)中的配置類的選擇性加載的過程。
  1. ☛ 文章要是勘誤或者知識點說的不正确,歡迎評論,畢竟這也是作者通過閱讀源碼獲得的知識,難免會有疏忽!
  2. ☛ 要是感覺文章對你有所幫助,不妨點個關注,或者移駕看一下作者的其他文集,也都是幹活多多哦,文章也在全力更新中。
  3. ☛ 著作權歸作者所有。商業轉載請聯系作者獲得授權,非商業轉載請注明出處!