SpringBoot 源碼分析 - 自動配置深度分析一
- refresh和自動配置大致流程
- 如何自動配置
- SpringBootApplication注解
- EnableAutoConfiguration注解
- AutoConfigurationImportSelector自動配置導入選擇器
- DeferredImportSelectorHandler的handle
- DeferredImportSelectorGroupingHandler的register注冊DeferredImportSelectorHolder
- DeferredImportSelectorGrouping
refresh和自動配置大致流程
如何自動配置
我們看下這段代碼,紅色框是什么放入的注冊類,其實這就是我們要注冊的配置類,自動裝配跟他有關:
public static void main(String[] args) {SpringApplication.run(SpringBootLearnApplication.class, args);}
為什么呢,因為他頭上有注解 SpringBootApplication
:
@SpringBootApplication
public class SpringBootLearnApplication
所以其實你只要傳一個頭上有這個注解的類就可以了,不一定要是main
方法的類。
SpringBootApplication注解
那為什么就有這個注解就能自動配置呢,我們來看看這個注解,其他你可以不管,但是EnableAutoConfiguration
你得看:
首先這個是一個配置類,可以被解析,因為有SpringBootConfiguration
注解,被Configuration
注解了:
這樣我們的SpringBootApplication
就類似于我們經常配置的java
配置類。有了這個前提,我們就可以先看這個配置類的解析過程,其實就是ConfigurationClassPostProcessor
的解析處理,解析流程我以前的spring
源碼文章都講過,其中processImports
的處理也特別講過,會先遞歸獲取所有import
進來的類,然后按不同類型進行判斷處理,重點就是這里啦,我們先來看下EnableAutoConfiguration
注解是不是有import
呢。
EnableAutoConfiguration注解
有個AutoConfigurationImportSelector
被import
,其實還有一個在AutoConfigurationPackage
注解里,暫時不說,重點是AutoConfigurationImportSelector
。
AutoConfigurationImportSelector自動配置導入選擇器
看下他的結構,左邊不用管,就是為了回調拿到一些屬性,好對容器操作,主要是右邊,我們前面spring
的文章講過ImportSelector
的原理,想看的朋友可以看下這篇文章,有這個基礎對下面的理解比較好,因為這里還有個DeferredImportSelector
,他會在ConfigurationClassParser
解析方法的最后來處理。
可以看到,他被處理的時候:
DeferredImportSelectorHandler
就是專門來處理這些DeferredImportSelector
的。
DeferredImportSelectorHandler的handle
首先會封裝一個持有器DeferredImportSelectorHolder
,如果deferredImportSelectors
為空,表示在被DeferredImportSelectorGroupingHandler
處理中,DeferredImportSelectorGroupingHandler
又是什么呢,其實我們要處理的DeferredImportSelectorHolder
會根據Group
進行分組,來區分不同的ImportSelector
,比如我們這個自動裝配的AutoConfigurationImportSelector
,是屬于AutoConfigurationGroup
類型的,分組處理方便,到時候只需要遍歷所有組中的ImportSelector
統一處理即可。因為處理的方式是迭代器循環,所以不能添加,只能直接處理,當然如果不為空,表示沒有在處理,可以添加到deferredImportSelectors
集合里。
public void handle(ConfigurationClass configClass, DeferredImportSelector importSelector) {DeferredImportSelectorHolder holder = new DeferredImportSelectorHolder(configClass, importSelector);if (this.deferredImportSelectors == null) {//直接處理DeferredImportSelectorGroupingHandler handler = new DeferredImportSelectorGroupingHandler();handler.register(holder);handler.processGroupImports();}else {this.deferredImportSelectors.add(holder);//添加}}
DeferredImportSelectorGroupingHandler的register注冊DeferredImportSelectorHolder
可以看到組處理器里面會有一個groupings
映射,就是來存放Group
類別和DeferredImportSelectorGrouping
映射的,同一個Group
類別里面可以很多個DeferredImportSelectorGrouping
,因為DeferredImportSelectorGrouping
里面有集合。
//自動裝配類型和組映射private final Map<Object, DeferredImportSelectorGrouping> groupings = new LinkedHashMap<>();//注解屬性和配置類的映射private final Map<AnnotationMetadata, ConfigurationClass> configurationClasses = new HashMap<>();//注冊分組public void register(DeferredImportSelectorHolder deferredImport) {Class<? extends Group> group = deferredImport.getImportSelector().getImportGroup();DeferredImportSelectorGrouping grouping = this.groupings.computeIfAbsent((group != null ? group : deferredImport),key -> new DeferredImportSelectorGrouping(createGroup(group)));//創建組grouping.add(deferredImport);//創建一個組,并加入DeferredImportSelectorHolderthis.configurationClasses.put(deferredImport.getConfigurationClass().getMetadata(),deferredImport.getConfigurationClass());//將注解屬性和ConfigurationClass映射}
DeferredImportSelectorGrouping
這里就是同一個組的會添加進deferredImports
集合。
其實是比較繞的,繞了幾層,我畫個圖看了清晰: