官網介紹
先來看看官網是怎么定義這個自動裝配的~
可以看到這里說,當你引入了某個 jar 依賴包時,Springboot 會嘗試根據這個依賴去自動配置 Spring 應用程序。
而且這里還說明了,你應該在 一個配置類 @Configuration 上選擇 @EnableAutoConfiguration 和 @SpringBootApplication 這其中的一個注解,來讓自動配置生效.
那么,知道這些信息后,我們就開始愉快地看源碼環節了~ 沖沖沖!
對了,探索的 Springboot 版本為 2.4.5
@SpringBootApplication
來到 @SpringBootApplication 注解中,可以發現它是一個組合注解,除了前面四個基本的元注解外,還有下面這三個 @SpringBootConfiguration , @EnableAutoConfiguration ,@ComponentScan
源碼如圖
@SpringBootConfiguration
我們先來看這第一個注解,如圖,可以發現它其實是一個 @Configuration 注解,@Configuration 注解的作用是將其作為一個配置類,來配置 Spring 的上下文,相當于 Spring 的 XML 配置文件中的 <beans>
源碼如圖
@ComponentScan
這個的作用就是 掃描指定路徑下的組件,并加入到 IOC 容器 中,相當于Spring 的 XML 配置文件中的 <context:component-scan/>
源碼如圖
可以發現它里面有一個 @Repeatable(ComponentScans.class) 注解,表示可重復使用@ComponentScan 注解
注意,這里會按照我們自定義的方式去排除一些類,具體是通過實現 TypeFilter 接口并重寫 match 方法來實現 。
小細節
這里還有個點要注意下~
AutoConfigurationExcludeFilter 會檢查配置類,如果該配置類和 META-INF/spring.factories 文件中的 EnableAutoConfiguration 對應的配置類一樣的話,會被排除掉~
@EnableAutoConfiguration
終于,來到本文的重點了
看到它的名字就知道它就是這個 自動配置 的主角了
源碼如圖
可以發現它是一個組合注解
先來看看這個注解1 @AutoConfigurationPackage
@AutoConfigurationPackage
從名字就可以看出它是一個 自動配置包路徑 的注解
源碼如圖
從這段注釋我們可以發現,當沒有配置這個 basePackages 或者 basePackageClasses 時,這個類就會自動將該注解所在的包作為基本路徑進行注冊
接著,我們再來看看這個框框里的內容~ @Import(
AutoConfigurationPackages.Registrar.class)
@Import
先來看看這個注解的作用吧
源碼如圖
可以發現它的作用也很簡單,就是導入組件,比如常見的 @Configuration 類或者ImportSelector 和
ImportBeanDefinitionRegistrar 的實現類,或者其他一些常規的組件如 @Component ,@Service 等等
Registrar
繼續看看這個 @Import(
AutoConfigurationPackages.Registrar.class) ,可以發現該注解導入的是 Registrar 類 , 那么我們繼續探索下,看看它干了什么~
源碼如圖
從該類的注解可以看出,它的作用是通過
ImportBeanDefinitionRegistrar **來保存這個基本包的路徑的 **
那么,講完第一點 ,我們簡單了解到這個 @AutoConfigurationPackage 就是用來配置基本包 ,我們接著再來看看第二點,這個 @Import(
AutoConfigurationImportSelector.class) 注解。
我們可以發現它導入了
AutoConfigurationImportSelector 類。
AutoConfigurationImportSelector
看這個名稱,可以大概知道它是一個 組件選擇器
關鍵步驟介紹
process
這個方法在獲取這些 Import 類時會被調用,具體可以看結尾的流程圖~
getAutoConfigurationEntry
獲取自動配置實體類 ,里面還有本文的重點~
getCandidateConfigurations
來到這里,可以發現它調用到這個 SpringFactoriesLoader ,這里就不得不提下這個 Springboot 的 SPI 機制了,另外它和我們上文(服務發現機制SPI居然是破壞者?! )中提到的 Java Spi 有什么不同呢 ?
再繼續往下看一下~
Springboot SPI機制
老規矩,看一眼注釋先 哈哈
spring.factories 文件
舉個栗子
# Run Listeners
org.springframework.boot.SpringApplicationRunListener=\
org.springframework.boot.context.event.EventPublishingRunListener
可以發現它加載的是 META-INF/spring.factories 這個文件 ,相比 java 的 META-INF/services ,有以下的不同點:
- 從名字上就可以發現很大的不同( 一個是 factories 文件,一個是以接口全名命名的文件 )。
- spring.factories 以一個聚合的作用,把相應的接口和實現類以 key = value 形式展現在 spring.factories 文件中。
- spring.factories 中的所有配置項會加載到我們的緩存中,以 Map<String,List<String>> 形式存儲,但不是所有的都會被實例化,被加載到 IOC 容器中,除了必要的類外( EventPublishingRunListener 等 ),還有滿足特定條件下的自動配置類會被加載到 IOC 容器中
滿足特定條件 ? 比如有沒有使用到這個依賴( pom 中的 starter)
自動配置類 ? 指以 AutoConfiguration 結尾的那些類
可以發現這種按需實現的機制比java的一股腦實現靈活多了~
實例解析
比如 這里從 spring.factories 文件中加載了130個自動配置類
但是實際使用中,經過過濾后只有這 30 個了
這里還根據 優先級 做了一些排序~
自動裝配流程圖
這里只摘了一些關鍵步驟~ ,具體流程太長了 ,得從 SpringApplication 源碼中的 refreshContext(context); 這里就先不介紹啦,后面有時間再寫一下分享下這個 [[Springboot源碼的啟動過程]]
同顏色的類名和方法塊對應~
圖中左下角的 processImports 方法,就是將這些自動配置類進行實例化,包括配置類里面的 @Import , @Bean 等 ,一步步加載到 Spring 的 IOC 容器中。
總結
一. Springboot 的自動裝配很重要的一點就是,就是要在配置類上開啟 @EnableAutoConfiguration 或者 @SpringBootApplication 注解,來讓自動配置生效。
二. 自動配置的核心是 Springboot 的 SPI 機制 ,以及組件選擇器
AutoConfigurationImportSelector,具體是通過其中的 getAutoConfigurationEntry 方法來獲取 SPI 中的自動配置類并進行過濾,最后通過 processImports 將配置類加載到 IOC 容器中,完成自動配置