Spring Boot 源碼學(xué)習(xí)系列
引言
前兩篇博文筆者帶大家從源碼深入了解了 Spring Boot 的自動裝配流程,其中自動配置過濾的實現(xiàn)由于篇幅限制,還未深入分析。
那么從本篇開始,Huazie 就帶大家走近 AutoConfigurationImportFilter
,一起從源碼解析 FilteringSpringBootCondition
、OnBeanCondition
、OnClassCondition
、OnWebApplicationCondition
的實現(xiàn)。
往期內(nèi)容
在開始本篇的內(nèi)容介紹之前,我們先來看看往期的系列文章【有需要的朋友,歡迎關(guān)注系列專欄】:
Spring Boot 源碼學(xué)習(xí) |
Spring Boot 項目介紹 |
Spring Boot 核心運行原理介紹 |
【Spring Boot 源碼學(xué)習(xí)】@EnableAutoConfiguration 注解 |
【Spring Boot 源碼學(xué)習(xí)】@SpringBootApplication 注解 |
【Spring Boot 源碼學(xué)習(xí)】走近 AutoConfigurationImportSelector |
【Spring Boot 源碼學(xué)習(xí)】自動裝配流程源碼解析(上) |
【Spring Boot 源碼學(xué)習(xí)】自動裝配流程源碼解析(下) |
主要內(nèi)容
在開始本篇內(nèi)容之前,我們再次來回顧一下上篇博文介紹的 AutoConfigurationImportFilter
的源碼和相關(guān)的類圖:
@FunctionalInterface
public interface AutoConfigurationImportFilter {
// 自動配置組件的過濾匹配
boolean[] match(String[] autoConfigurationClasses, AutoConfigurationMetadata autoConfigurationMetadata);
}
通過上面的關(guān)聯(lián)類圖,我們可以看到 AutoConfigurationImportFilter
接口實際上是由抽象類 FilteringSpringBootCondition
來實現(xiàn)的,另外翻看它的源碼,該抽象類還定義了一個抽象方法 getOutcomes
,然后 OnBeanCondition
、OnClassCondition
、OnWebApplicationCondition
繼承該抽象類,實現(xiàn) getOutcomes
方法,完成實際的過濾匹配操作。
本篇,我們就從源碼入手重點介紹 FilteringSpringBootCondition
:
1. match 方法
上一篇博文我們已經(jīng)從 FilteringSpringBootCondition
的部分源碼進行了分析,它的 match
方法主要是調(diào)用 getOutcomes
方法,并將其返回的結(jié)果轉(zhuǎn)換成布爾數(shù)組。而這個 getOutcomes
方法是過濾匹配的核心功能,由抽象類 FilteringSpringBootCondition 的子類來實現(xiàn)它。
這里再簡單回顧一下 match
方法的處理邏輯:
@Override
public boolean[] match(String[] autoConfigurationClasses, AutoConfigurationMetadata autoConfigurationMetadata) {
ConditionEvaluationReport report = ConditionEvaluationReport.find(this.beanFactory);
// 調(diào)用 由子類實現(xiàn)的 getOutcomes 方法,完成實際的過濾匹配操作
ConditionOutcome[] outcomes = getOutcomes(autoConfigurationClasses, autoConfigurationMetadata);
boolean[] match = new boolean[outcomes.length];
// 將 getOutcomes 方法返回結(jié)果轉(zhuǎn)換成布爾數(shù)組
for (int i = 0; i < outcomes.length; i++) {
match[i] = (outcomes[i] == null || outcomes[i].isMatch());
if (!match[i] && outcomes[i] != null) {
logOutcome(autoConfigurationClasses[i], outcomes[i]);
if (report != null) {
report.recordConditionEvaluation(autoConfigurationClasses[i], this, outcomes[i]);
}
}
}
return match;
}
上述代碼中,我們可以看到,將 getOutcomes
方法返回結(jié)果轉(zhuǎn)換成布爾數(shù)組的循環(huán)邏輯中有一段代碼如下:
match[i] = (outcomes[i] == null || outcomes[i].isMatch());
這里是將返回結(jié)果轉(zhuǎn)換成布爾值,分別是:
- 如果匹配結(jié)果為
null
,認為符合匹配要求, 設(shè)置match[i] = true
; - 如果匹配結(jié)果不為
null
,并且 匹配對象的isMatch == true
,也認為符合匹配要求, 設(shè)置match[i] = true
;
這個時候,我們就能理解 上篇博文講到的 不符合過濾匹配要求,則清空當前的自動配置組件 的邏輯:
當然 FilteringSpringBootCondition
內(nèi)還有其他的內(nèi)容,這些內(nèi)容在它的子類中也將使用到,我們先提前了解下,以便后續(xù)能更好地理解子類的功能實現(xiàn)。
2. ClassNameFilter 枚舉類
首先查看 ClassNameFilter
枚舉類的源碼【Spring Boot 2.7.9】:
protected enum ClassNameFilter {
PRESENT {
@Override
public boolean matches(String className, ClassLoader classLoader) {
return isPresent(className, classLoader);
}
},
MISSING {
@Override
public boolean matches(String className, ClassLoader classLoader) {
return !isPresent(className, classLoader);
}
};
abstract boolean matches(String className, ClassLoader classLoader);
// ....
}
ClassNameFilter
枚舉類包含兩個枚舉常量,分別是 PRESENT
和 MISSING
;這兩個枚舉常量都實現(xiàn)了 ClassNameFilter
枚舉類定義的 matches
的抽象方法,其中
-
PRESENT
中的matches
返回isPresent(className, classLoader);
-
MISSING
中的matches
返回!isPresent(className, classLoader);
我們繼續(xù)看 isPresent 方法,分析一下它的功能:
static boolean isPresent(String className, ClassLoader classLoader) {
if (classLoader == null) {
classLoader = ClassUtils.getDefaultClassLoader();
}
try {
resolve(className, classLoader);
return true;
}
catch (Throwable ex) {
return false;
}
}
protected static Class<?> resolve(String className, ClassLoader classLoader) throws ClassNotFoundException {
if (classLoader != null) {
return Class.forName(className, false, classLoader);
}
return Class.forName(className);
}
上述 isPresent
方法的邏輯其實也并不復(fù)雜,就是通過類加載器去加載指定的類【即 className 字符串對應(yīng)的類】:
- 如果指定的類加載成功,則直接返回
true
; - 如果指定的類加載失敗,則要拋出異常,捕獲異常后,返回
false
。
那顯然 ClassNameFilter.PRESENT.matches(className, classLoader)
用于校驗指定的類是否加載成功:
- 如果指定的類加載成功,則返回
true
; - 如果指定的類加載失敗,則返回
false
。
而 ClassNameFilter.MISSING.matches(className, classLoader)
用于校驗指定的類是否加載失敗:
- 如果指定的類加載失敗,則返回
true
; - 如果指定的類加載成功,則返回
false
。
3. filter 方法
繼續(xù)翻看 FilteringSpringBootCondition
源碼,還有一個 filter
方法需要重點介紹下:
protected final List<String> filter(Collection<String> classNames, ClassNameFilter classNameFilter, ClassLoader classLoader) {
if (CollectionUtils.isEmpty(classNames)) {
return Collections.emptyList();
}
List<String> matches = new ArrayList<>(classNames.size());
for (String candidate : classNames) {
if (classNameFilter.matches(candidate, classLoader)) {
matches.add(candidate);-
}
}
return matches;
}
結(jié)合上面的 ClassNameFilter
枚舉類,我們可以很容易理解上面的代碼邏輯。文章來源:http://www.zghlxwxcb.cn/news/detail-706983.html
- 如果
classNameFilter
是ClassNameFilter.PRESENT
,則filter
方法獲取指定的類集合中加載成功的類集合【即匹配成功的類集合】; - 如果
classNameFilter
是ClassNameFilter.MISSING
,則filter
方法獲取指定的類集合中加載失敗的類集合【即匹配失敗的類集合】。
總結(jié)
本篇 Huazie 帶大家介紹了自動配置過濾匹配的核心父類 FilteringSpringBootCondition
,這對于筆者后續(xù)博文詳解它的三個子類【OnBeanCondition
、OnClassCondition
、OnWebApplicationCondition
】非常重要,敬請期待?。?!。文章來源地址http://www.zghlxwxcb.cn/news/detail-706983.html
到了這里,關(guān)于【Spring Boot 源碼學(xué)習(xí)】深入 FilteringSpringBootCondition的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!