目錄
- AutoConfigurationImportFilter的使用
- AutoConfigurationImportFilter過濾基本流程
-
- 1.擷取META-INF/spring.factories中配置的所有過濾器
- 2.周遊所有過濾器,并執行其match方法
- 3.拼接自動配置類名和注解名為特定字元
- 4.根據字元串查詢中繼資料中配置的類
- 5.嘗試用類加載器加載該類
- 6.加載成功則比對成功,抛出異常則比對失敗
- 參考
AutoConfigurationImportFilter的使用
在AutoConfigurationImportSelector實作的selectImports方法中會通過AutoConfigurationImportFilter的相關接口實作來進行自動配置類的過濾
private List<String> filter(List<String> configurations, AutoConfigurationMetadata autoConfigurationMetadata) {
long startTime = System.nanoTime();
String[] candidates = StringUtils.toStringArray(configurations);
boolean[] skip = new boolean[candidates.length];
boolean skipped = false;
//擷取META-INF/spring.factories中配置的所有過濾器
Iterator var8 = this.getAutoConfigurationImportFilters().iterator();
//周遊所有過濾器,并執行其match方法
while(var8.hasNext()) {
AutoConfigurationImportFilter filter = (AutoConfigurationImportFilter)var8.next();
this.invokeAwareMethods(filter);
boolean[] match = filter.match(candidates, autoConfigurationMetadata);
for(int i = 0; i < match.length; ++i) {
if (!match[i]) {
skip[i] = true;
candidates[i] = null;
skipped = true;
}
}
}
if (!skipped) {
return configurations;
} else {
List<String> result = new ArrayList(candidates.length);
int numberFiltered;
for(numberFiltered = 0; numberFiltered < candidates.length; ++numberFiltered) {
if (!skip[numberFiltered]) {
result.add(candidates[numberFiltered]);
}
}
if (logger.isTraceEnabled()) {
numberFiltered = configurations.size() - result.size();
logger.trace("Filtered " + numberFiltered + " auto configuration class in " + TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - startTime) + " ms");
}
return new ArrayList(result);
}
}
protected List<AutoConfigurationImportFilter> getAutoConfigurationImportFilters() {
return SpringFactoriesLoader.loadFactories(AutoConfigurationImportFilter.class, this.beanClassLoader);
}
AutoConfigurationImportFilter過濾基本流程
- 擷取META-INF/spring.factories中配置的所有過濾器
- 周遊所有過濾器,并執行其match方法
- 拼接自動配置類名和注解名為特定字元
- 根據字元串查詢中繼資料中配置的類
- 嘗試用類加載器加載該類
- 加載成功則比對成功,抛出異常則比對失敗
1.擷取META-INF/spring.factories中配置的所有過濾器
protected List<AutoConfigurationImportFilter> getAutoConfigurationImportFilters() {
return SpringFactoriesLoader.loadFactories(AutoConfigurationImportFilter.class, this.beanClassLoader);
}
通過loadFactories方法在META-INF/spring.factories中擷取所有的篩選條件,包括:
- OnBeanCondition
- OnClassCondition
- OnWebApplicationCondition
2.周遊所有過濾器,并執行其match方法
周遊到的過濾器都實作了FilteringSpringBootCondition類,而FilteringSpringBootCondition則實作了AutoConfigurationImportFilter類,其中的match方法用來判斷條件是否符合,match方法的實作方法如下:
public boolean[] match(String[] autoConfigurationClasses, AutoConfigurationMetadata autoConfigurationMetadata) {
ConditionEvaluationReport report = ConditionEvaluationReport.find(this.beanFactory);
ConditionOutcome[] outcomes = this.getOutcomes(autoConfigurationClasses, autoConfigurationMetadata);
boolean[] match = new boolean[outcomes.length];
for(int i = 0; i < outcomes.length; ++i) {
match[i] = outcomes[i] == null || outcomes[i].isMatch();
if (!match[i] && outcomes[i] != null) {
this.logOutcome(autoConfigurationClasses[i], outcomes[i]);
if (report != null) {
report.recordConditionEvaluation(autoConfigurationClasses[i], this, outcomes[i]);
}
}
}
return match;
}
其中主要的判斷邏輯,是在getOutcomes方法中,各過濾器實作了相應的getOutcomes方法用來進行條件判斷。
3.拼接自動配置類名和注解名為特定字元
在各過濾器實作的getOutcomes方法中,對需要過濾的自動配置類進行分半處理,并且單獨提取每一個自動配置類的條件進行判斷,最後進行判斷的步驟為:
private ConditionOutcome[] getOutcomes(String[] autoConfigurationClasses, int start, int end, AutoConfigurationMetadata autoConfigurationMetadata) {
ConditionOutcome[] outcomes = new ConditionOutcome[end - start];
for(int i = start; i < end; ++i) {
String autoConfigurationClass = autoConfigurationClasses[i];
if (autoConfigurationClass != null) {
String candidates = autoConfigurationMetadata.get(autoConfigurationClass, "ConditionalOnClass");
if (candidates != null) {
outcomes[i - start] = this.getOutcome(candidates);
}
}
}
return outcomes;
}
private ConditionOutcome getOutcome(String candidates) {
try {
if (!candidates.contains(",")) {
return this.getOutcome(candidates, this.beanClassLoader);
}
String[] var2 = StringUtils.commaDelimitedListToStringArray(candidates);
int var3 = var2.length;
for(int var4 = 0; var4 < var3; ++var4) {
String candidate = var2[var4];
ConditionOutcome outcome = this.getOutcome(candidate, this.beanClassLoader);
if (outcome != null) {
return outcome;
}
}
} catch (Exception var7) {
}
return null;
}
private ConditionOutcome getOutcome(String className, ClassLoader classLoader) {
return ClassNameFilter.MISSING.matches(className, classLoader) ? ConditionOutcome.noMatch(ConditionMessage.forCondition(ConditionalOnClass.class, new Object[0]).didNotFind("required class").items(Style.QUOTE, new Object[]{className})) : null;
}
其中,通過PropertiesAutoConfigurationMetadata實作了AutoConfigurationMetadata的get方法,以拼接後的字元串作為key,從META-INF/spring-autoconfigure-metadata.properties檔案中得到該條件對應的類:
public String get(String className, String key, String defaultValue) {
//拼接自動配置類名和注解名為特定字元
//根據字元串查詢中繼資料中配置的類
String value = this.properties.getProperty(className + "." + key);
return value != null ? value : defaultValue;
}
4.根據字元串查詢中繼資料中配置的類
5.嘗試用類加載器加載該類
獲得類名稱之後,則采用ClassNameFilter.MISSING的matches方法進行判斷:
protected static enum ClassNameFilter {
PRESENT {
public boolean matches(String className, ClassLoader classLoader) {
return isPresent(className, classLoader);
}
},
MISSING {
public boolean matches(String className, ClassLoader classLoader) {
return !isPresent(className, classLoader);
}
};
private ClassNameFilter() {
}
public abstract boolean matches(String className, ClassLoader classLoader);
public static boolean isPresent(String className, ClassLoader classLoader) {
if (classLoader == null) {
classLoader = ClassUtils.getDefaultClassLoader();
}
//加載成功則比對成功,抛出異常則比對失敗
try {
forName(className, classLoader);
return true;
} catch (Throwable var3) {
return false;
}
}
//嘗試用類加載器加載該類
private static Class<?> forName(String className, ClassLoader classLoader) throws ClassNotFoundException {
return classLoader != null ? classLoader.loadClass(className) : Class.forName(className);
}
}
6.加載成功則比對成功,抛出異常則比對失敗
參考
(《Spring Boot 技術内幕》)