《Spring Boot 源碼學習系列》
引言
上篇博文,筆者帶大家從整體上了解了AutoConfigurationImportSelector 自動裝配邏輯的核心功能及流程,由于篇幅有限,更加細化的功能及流程詳解還沒有介紹。本篇開始將從其源碼入手,重點解析細化后的自動裝配流程源碼。
往期內容
在開始本篇的內容介紹之前,我們先來看看往期的系列文章【有需要的朋友,歡迎關注系列專欄】:
Spring Boot 源碼學習 |
Spring Boot 項目介紹 |
Spring Boot 核心運行原理介紹 |
【Spring Boot 源碼學習】@EnableAutoConfiguration 注解 |
【Spring Boot 源碼學習】@SpringBootApplication 注解 |
【Spring Boot 源碼學習】走近 AutoConfigurationImportSelector |
主要內容
下面就讓我們從 AutoConfigurationImportSelector
的 selectImports
方法源碼入手,開始了解自動裝配流程。
下面來看一下 selectImports 的相關源碼【Spring Boot 2.7.9】:
@Override
public String[] selectImports(AnnotationMetadata annotationMetadata) {
if (!isEnabled(annotationMetadata)) {
return NO_IMPORTS;
}
AutoConfigurationEntry autoConfigurationEntry = getAutoConfigurationEntry(annotationMetadata);
return StringUtils.toStringArray(autoConfigurationEntry.getConfigurations());
}
protected AutoConfigurationEntry getAutoConfigurationEntry(AnnotationMetadata annotationMetadata) {
if (!isEnabled(annotationMetadata)) {
return EMPTY_ENTRY;
}
AnnotationAttributes attributes = getAttributes(annotationMetadata);
List<String> configurations = getCandidateConfigurations(annotationMetadata, attributes);
configurations = removeDuplicates(configurations);
Set<String> exclusions = getExclusions(annotationMetadata, attributes);
checkExcludedClasses(configurations, exclusions);
configurations.removeAll(exclusions);
configurations = getConfigurationClassFilter().filter(configurations);
fireAutoConfigurationImportEvents(configurations, exclusions);
return new AutoConfigurationEntry(configurations, exclusions);
}
1. 自動配置開關
檢查自動配置是否開啟的邏輯位于 AutoConfigurationImportSelector
的 selectImports
方法中的第一段代碼。如果開啟自動配置,則繼續(xù)執(zhí)行后續(xù)操作;否則就返回空數組。
檢查自動配置是否開啟的源碼,如下所示:
@Override
public String[] selectImports(AnnotationMetadata annotationMetadata) {
if (!isEnabled(annotationMetadata)) {
return NO_IMPORTS;
}
// ...省略
}
從上面的源碼可以看出,這里主要使用了 isEnabled
方法來判斷自動配置是否開啟;其中該方法返回 true,表示開啟自動配置,返回 false,表示關閉自動配置。
我們來看一下它的源碼,如下所示:
protected boolean isEnabled(AnnotationMetadata metadata) {
if (getClass() == AutoConfigurationImportSelector.class) {
return getEnvironment().getProperty(EnableAutoConfiguration.ENABLED_OVERRIDE_PROPERTY, Boolean.class, true);
}
return true;
}
通過閱讀上述 isEnabled
方法源碼,我們可以看出,如果當前類為 AutoConfigurationImportSelector
,會從環(huán)境中獲取 key
為EnableAutoConfiguration.ENABLED_OVERRIDE_PROPERTY
的配置屬性,而筆者前面的系列博文如果大家看過的話,介紹 EnableAutoConfiguration
注解時,就說了這個常量的值為 spring.boot.enableautoconfiguration
。
如果該屬性的配置獲取不到,則默認為 true
,也就是默認會開啟自動配置。如果當前類為其他類,也則默認直接返回 true
。
如果想覆蓋或重置該配置,我們可以在 application.properties 或 application.yml 中針對 spring.boot.enableautoconfiguration
參數進行配置。
以 application.properties
配置關閉自動配置為例,如下所示 :
spring.boot.enableautoconfiguration=false
2. 加載自動配置組件
接下來,我們看到調用 getAutoConfigurationEntry
的代碼,它是用來封裝將被引入的自動配置信息:
AutoConfigurationEntry autoConfigurationEntry = getAutoConfigurationEntry(annotationMetadata);
然后我們進入 getAutoConfigurationEntry
方法,看到了獲取注解屬性的邏輯,如下所示:
AnnotationAttributes attributes = getAttributes(annotationMetadata);
// 從 AnnotationMetadata 返回適當的 AnnotationAttributes。默認情況下,此方法將返回 getAnnotationClass() 的屬性。
protected AnnotationAttributes getAttributes(AnnotationMetadata metadata) {
String name = getAnnotationClass().getName();
AnnotationAttributes attributes = AnnotationAttributes.fromMap(metadata.getAnnotationAttributes(name, true));
Assert.notNull(attributes, () -> "No auto-configuration attributes found. Is " + metadata.getClassName()
+ " annotated with " + ClassUtils.getShortName(name) + "?");
return attributes;
}
我們啟動先前建的 Spring Boot 項目的應用類,在 getAttributes
方法最后 return
處打個斷點,我們可以看到如下的邏輯:
了解到這,可以開始加載自動配置的組件了,也就是下面的代碼:
// 通過 SpringFactoriesLoader 類提供的方法加載類路徑中META-INF目錄下的
// spring.factories文件中針對 EnableAutoConfiguration 的注解配置類
List<String> configurations = getCandidateConfigurations(annotationMetadata, attributes);
我們進入 getCandidateConfigurations
方法中, 相關源碼如下所示:
protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {
List<String> configurations = new ArrayList<>(
SpringFactoriesLoader.loadFactoryNames(getSpringFactoriesLoaderFactoryClass(), getBeanClassLoader()));
ImportCandidates.load(AutoConfiguration.class, getBeanClassLoader()).forEach(configurations::add);
Assert.notEmpty(configurations,
"No auto configuration classes found in META-INF/spring.factories nor in META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports. If you "
+ "are using a custom packaging, make sure that file is correct.");
return configurations;
}
通過閱讀上述源碼,我們可以看出這里使用了 SpringFactoriesLoader
類提供的loadFactoryNames
方法來加載的。其中 loadFactoryNames
方法的第一個參數為 getSpringFactoriesLoaderFactoryClass
方法返回的 EnableAutoConfiguration.class
。
protected Class<?> getSpringFactoriesLoaderFactoryClass() {
return EnableAutoConfiguration.class;
}
通過翻看 loadFactoryNames
方法對應的源碼,我們可以知道它是讀取的 META-INF/spring.factories
中的配置,并且只會讀取配置文件中針對自動配置的注冊類【即 EnableAutoConfiguration 相關的配置信息】。
SpringFactoriesLoader
類的 loadFactoryNames
方法相關源碼,由于篇幅有限,這里就不貼出來了,感興趣的朋友可以自行查閱,Spring Boot 中后續(xù)會有很多地方用到它,比如用于監(jiān)聽的 Listeners
和用于過濾的 Filters
。
實際上 在 Spring Boot 2.7.9 版本中, 它自己內部的 META-INF/spring.factories
中有關自動配置的注冊類的配置信息已經被去除掉了,不過其他外圍的 jar 中可能有自己的 META-INF/spring.factories
文件,它里面也有關于自動配置注冊類的配置信息;
另外我們在 getCandidateConfigurations
方法中,也看到了另一行代碼獲取自動配置注冊類的信息,如下所示:
ImportCandidates.load(AutoConfiguration.class, getBeanClassLoader()).forEach(configurations::add);
這里的代碼其實就是讀取的如下截圖的配置信息【同 META-INF/spring.factories
一樣,下面的配置也可能存在于不同的 jar 包中 】:
我們啟動先前建的 Spring Boot 項目的應用類,在 getCandidateConfigurations
方法 ImportCandidates
類調用處打個斷點,我們可以看到如下的截圖【這里 configurations
目前還是空數據,說明從 META-INF/spring.factories
沒有獲取到自動配置注冊類的相關信息,因為我們只引入了 Spring Boot 項目,并且它內部的 META-INF/spring.factories
中的確刪除了自動配置注冊類的相關信息】:
在 getCandidateConfigurations
方法 最后 return
處打個斷點,我們可以看到如下的截圖【這里 configurations
中加載的都是自動配置的注冊類,也就是 上述 ImportCandidates##load
加載的信息,這里讀取的是 META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports
中的配置信息】:
3. 自動配置組件去重
因為上述加載的自動配置注冊類,默認加載的是 ClassLoader 下面的所有 META-INF/spring.factories
或 META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports
文件中的配置,所以就有可能出現在不同的jar包中有重復配置的情況。
Spring Boot 中則使用了 Java
中 Set 集合數據不可重復的特點,來實現去重處理,如下所示:文章來源:http://www.zghlxwxcb.cn/news/detail-629958.html
// 對獲得的注解配置類集合進行去重處理,防止多個項目引入同樣的配置類
configurations = removeDuplicates(configurations);
// 利用 Set 集合數據不可重復的特點,來實現去重處理
protected final <T> List<T> removeDuplicates(List<T> list) {
return new ArrayList<>(new LinkedHashSet<>(list));
}
總結
本篇 Huazie 帶大家通讀了 Spring Boot 自動裝配邏輯的部分源碼,詳細分析了加載自動裝配的流程,剩下排除和過濾自動配置的流程將在下一篇繼續(xù)講解。內容較多,能夠看到這的小伙伴,Huazie 在這感謝各位的支持。后續(xù)我將持續(xù)輸出有關 Spring Boot 源碼學習系列的博文,想要及時了解更新的朋友,訂閱這里即可。文章來源地址http://www.zghlxwxcb.cn/news/detail-629958.html
到了這里,關于【Spring Boot 源碼學習】自動裝配流程源碼解析(上)的文章就介紹完了。如果您還想了解更多內容,請在右上角搜索TOY模板網以前的文章或繼續(xù)瀏覽下面的相關文章,希望大家以后多多支持TOY模板網!