第二章 spring boot核心运行原理 (2)

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);
	}

解释上面的一些变量或参数:

  1. configurations: List,经过初次过滤之后的自动配置组件列表。
  2. autoConfigurationMetadata:AutoConigurationMetadata,元数据文件META-INF/spring-autoconfigurationImportFilter的Filter列表
  3. 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方法,最后进行事件广播。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值