SpringBoot 自動配置原理(三)
上一篇文章中,我們提到AutoConfigurationImportSelector.AutoConfigurationGroup#process會將classpath下所有的META-INFO/spring.factories
中的org.springframework.boot.autoconfigure.EnableAutoConfiguration
屬性中的自動配置類讀取進來。spring.factories
中宣告的自動裝配類非常的多,難道我們每一個自動配置類都需要處理嗎?答案當然是否定的,這篇文章來探討一下SpringBoot是如何過濾掉不需要自動配置的類的。
AutoConfigurationImportSelector#getAutoConfigurationEntry
先來回顧一下方法getAutoConfigurationEntry
protected AutoConfigurationEntry getAutoConfigurationEntry(AnnotationMetadata annotationMetadata) { if (!isEnabled(annotationMetadata)) { return EMPTY_ENTRY; } AnnotationAttributes attributes = getAttributes(annotationMetadata); //讀取spring.factories中的自動配置類 List<String> configurations = getCandidateConfigurations(annotationMetadata, attributes); configurations = removeDuplicates(configurations); //讀取@SpringBootApplication中excluded宣告的要排除的自動配置類 Set<String> exclusions = getExclusions(annotationMetadata, attributes); checkExcludedClasses(configurations, exclusions); configurations.removeAll(exclusions); //過濾不需要裝配的自動配置類 configurations = getConfigurationClassFilter().filter(configurations); fireAutoConfigurationImportEvents(configurations, exclusions); return new AutoConfigurationEntry(configurations, exclusions); }
這裡的關鍵就在這個filter()方法中。
List<String> filter(List<String> configurations) { long startTime = System.nanoTime(); String[] candidates = StringUtils.toStringArray(configurations); boolean skipped = false; //這裡的filters其實是對@Conditional系列註解進行判斷 //這裡進行斷點的話可以發現filters中是三個類,OnClassCondition\OnBeanCondition\OnWebApplicationCondition for (AutoConfigurationImportFilter filter : this.filters) { boolean[] match = filter.match(candidates, this.autoConfigurationMetadata); for (int i = 0; i < match.length; i++) { if (!match[i]) { candidates[i] = null; skipped = true; } } } if (!skipped) { return configurations; } List<String> result = new ArrayList<>(candidates.length); for (String candidate : candidates) { if (candidate != null) { result.add(candidate); } } if (logger.isTraceEnabled()) { int numberFiltered = configurations.size() - result.size(); logger.trace("Filtered " + numberFiltered + " auto configuration class in " + TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - startTime) + " ms"); } return result; }
@Conditional
我們任意點進一個spring.factories中的自動配置類,我們或多或少的可以看到如@ConditionalOnClass這樣的註解,上面講到的filter()方法就會對這些@Conditional註解進行過濾。這裡簡單介紹幾個常見的@Conditional註解
-
@ConditionalOnClass
這個註解用於判斷某個類是否存在於classpath中,如果存在則進行自動配置。
-
@ConditionalOnBean
這個註解用於判斷某個Bean是否存在於IoC容器中,如果存在則進行自動配置。
-
@ConditionalOnMissingClass
這個註解用於判斷某個類是否存在於classpath中,如果不存在則進行自動配置。
-
@ConditionalOnMissingBean
這個註解用於判斷某個Bean是否存在於IoC容器中,如果不存在則進行自動配置。
經過過濾之後SpringBoot就會得到一個確定需要自動配置的類的全限定類名列表,之後的工作就交給Spring來完成了。
總結
spring.factories中的自動配置類並不是都需要自動配置,會通過在類上標註@Conditional註解的方式來告訴SpringBoot哪些類滿足自動配置的需求,最後將經過過濾的自動配置類交給Spring來解析。