2.3.8 @EnableAutoConfiguration过滤自动配置组件
当初步完成自动配置组件排除工作之后,AutoConfigurationImportSelector会结合在此之前获得的AutoConfigurationMetadata对象,对组件进行再次过滤.
代码如下:
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;
for (AutoConfigurationImportFilter filter : getAutoConfigurationImportFilters()) {
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;
}
List<String> result = new ArrayList<>(candidates.length);
for (int i = 0; i < candidates.length; i++) {
if (!skip[i]) {
result.add(candidates[i]);
}
}
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 new ArrayList<>(result);
}
protected List<AutoConfigurationImportFilter> getAutoConfigurationImportFilters() {
return SpringFactoriesLoader.loadFactories(AutoConfigurationImportFilter.class, this.beanClassLoader);
}
解释上面的一些变量或参数:
- configurations: List,经过初次过滤之后的自动配置组件列表。
- autoConfigurationMetadata:AutoConigurationMetadata,元数据文件META-INF/spring-autoconfigurationImportFilter的Filter列表
- List: META-INF.spring.factories中配置key为AutoConfigurationImportFilter的Filter列表。
getAutoConfigurationImportFilters方法是通过SpringFactoriesLoader的loadFactories方法将META-INF/spring.factories中配置key为Auto ConfigurationImportFilter的值进行加载。
下面是META-INF/spring.factories文件中相关配置的具体内容:
# Auto Configuration Import Filters
org.springframework.boot.autoconfigure.AutoConfigurationImportFilter=\
org.springframework.boot.autoconfigure.condition.OnBeanCondition,\
org.springframework.boot.autoconfigure.condition.OnClassCondition,\
org.springframework.boot.autoconfigure.condition.OnWebApplicationCondition
在spring-boot-autoconfigure中默认配置了3个筛选条件,OnBeanCondition,OnClassCondition和OnWebApplication,它们均实现了AutoConfigurationImportFilter接口。
明确上述信息之后,该filter方法的过滤功能更容易看懂了。简而言之就是:对自动配置组件列表进行再次过滤,过滤条件为该列表中自动配置的注解得包含在@OnBeanCondition、OnClassCondition和OnWebApplicationCondition中指定的注解,依次包含这三个。也就是下面这段代码:
for (AutoConfigurationImportFilter filter : getAutoConfigurationImportFilters()) {
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;
}
}
}
接下来需要知道,AutoConfigurationMetadata对应的元数据和AutoConfigurationImportFilter接口及其实现类是如何进行具体筛选的。
用来过滤自动配置类的接口AutoConfigurationImportFilter使用方法match来筛选需要过滤的配置类:
@FunctionalInterface
public interface AutoConfigurationImportFilter {
boolean[] match(String[] autoConfigurationClasses,
AutoConfigurationMetadata autoConfigurationMetadata);
}
match方法接受两个参数,一个是待过滤的自动配置类数组,另一个是自动配置的元数据信息。match返回的结果为匹配过滤后的结果布尔数组,数组大小与第一个参数相同,如果需要排除,设置对应的值为true。
AutoConfigurationImportFilter接口的match方法主要在其抽象子类中实现,而抽象子类FilteringSpringBootCondition在实现match方法的同时有定义了新的抽象方法getOutcomes,继承该抽象类的其他3个子类均实现了getOutcomes方法,这个方法(getOutcomes)就是相关的过滤核心功能的实现。
在3个子类中,选择OnClassCondition来具体说明执行过程。首先看一下入口方法getOutcomes的源代码。
Spring Boot当前版本对getOutcomes方法进行了性能优化,根据处理器的情况不同采用了不同的方式进行操作。如果有多处理器,采用后台线程。否则,getOutcomes直接创建内部类StandardOutcomesResolver来处理。
核心功能在内部类StandardOutcomesResolver的resolveOutcomes方法中实现。
内部类StandardOutcomesResolver的源代码重点关注getOutcomes方法的实现,它实现了获取元数据中指定配置,间接调用getOutcome(String className,ClassLoader classLoader)方法来判断该类是否符合条件,
在获取元数据指定的功能时用到了AutoConfigurationMetadata接口的get(String className, String key)方法,而该方法由类AutoConfigurationMetadataLoaderl来实现。该类会加载META-INF/spring-autoconfigure-metadata.properties中的配置。
AutoConfigurationMetadataLoader的内部类PropertiesAutoConfigurationMetadata实现了AutoConfigurationMetadata接口的具体方法,其中包含我们用到的get(String className,String key)方法。
根据get的实现过程,我们不难发现,在getOutcomes方法中获取到的candidates,其实就是META-INF/spring-autoconfigure-metadata.properties文件中配置的key为自动加载注解类+"."+"ConditionalOnClass"的字符串,而值为其获得的值。
在获取到对应的candidates值之后,最终会调用getOutcomes(String className, ClassLoader classLoader)方法,并在其中使用枚举类ClassNameFilter.MISSING的matches方法来判断candidates值是否匹配。而枚举类ClassNameFilter位于OnClassCondition继承的抽象类FilteringSpringBootCondition中。
枚举类ClassNameFilter里面是通过加载类是否发生异常来判断该类是否存在的。如果加载成功,即没有抛出异常就说明ClassNameFilter匹配成功。否者就匹配失败。
2.3.9 @EnableAutoConfiguration事件注册
在完成了以上步骤的过滤、筛选之后,我们最终获得了要进行自动配置的类的集合,在将该集合返回之前,在AutoConfogurationImportFSelector类中完成最后异步操作就是相关事件的封装和广播,相关代码如下:
private void fireAutoConfigurationImportEvents(List<String> configurations, Set<String> exclusions) {
List<AutoConfigurationImportListener> listeners = getAutoConfigurationImportListeners();
if (!listeners.isEmpty()) {
AutoConfigurationImportEvent event = new AutoConfigurationImportEvent(this, configurations, exclusions);
for (AutoConfigurationImportListener listener : listeners) {
invokeAwareMethods(listener);
listener.onAutoConfigurationImportEvent(event);
}
}
}
protected List<AutoConfigurationImportListener> getAutoConfigurationImportListeners() {
return SpringFactoriesLoader.loadFactories(AutoConfigurationImportListener.class, this.beanClassLoader);
}
以上代码首先通过SpringFactoriesLoader类提供的loadFactpories方法将spring.factories中配置的接口AutoConfigurationImportListener的实现类加载出来。然后,将筛选出的自动配置类集合和排除的自动配置类集合封装成AutoConfigurationImportEvent事件对象,并传入该事件对象通过监听器提供的onAutoConfigurationImportEvent方法,最后进行事件广播。