SpringBoot源码学习系列——自动配置原理(二)

AutoConfigurationImportSelector解析

@EnableAutoConfiguration 可以看到,其主要功能通过@Import(AutoConfigurationImportSelector.class)实现。

@Inherited
@AutoConfigurationPackage
@Import(AutoConfigurationImportSelector.class)
public @interface EnableAutoConfiguration {}

@Import和ImportSelector接口

@Import注解

@Import提供导入配置类的功能,可导入使用了@Configuration注解的类或实现了ImportSelectorImportBeanDefinitionRegistrar的类

ImportSelector接口

public interface ImportSelector {
	/**
	 * 提供了参数为AnnotationMetadata类型的方法,AnnotationMetadata包含@Import的注解信息
	 * 即selectImports方法根据@Import注解的value信息返回配置类的全类名,字符串数组形式
	 */
	String[] selectImports(AnnotationMetadata importingClassMetadata);

}

如下图所示,可以看到@EnableAutoConfiguration中@Import(AutoConfigurationImportSelector.class)AutoConfigurationImportSelector实现自DeferredImportSelector接口,DeferredImportSelector接口继承自ImportSelector
SpringBoot源码学习系列——自动配置原理(二)_第1张图片
DeferredImportSelector接口与ImportSelector接口的不同:

  • DeferredImportSelector:完成使用了@Configuration等注解的类加载后,再加载selectImports方法返回的指定的配置类
  • ImportSelector:完成使用了@Configuration等注解的类加载前,加载selectImports方法返回的指定的配置类
    下面对这一不同进行分析:
    DeferredImportSelector 源码可看出,DeferredImportSelector 提供了Group接口
public interface DeferredImportSelector extends ImportSelector {

	/**
	 * Return a specific import group.
	 * 

The default implementations return {@code null} for no grouping required. * @return the import group class, or {@code null} if none * @since 5.0 */ @Nullable default Class<? extends Group> getImportGroup() { return null; } /** * Interface used to group results from different import selectors. */ interface Group { /** * Process the {@link AnnotationMetadata} of the importing @{@link Configuration} * class using the specified {@link DeferredImportSelector}. */ void process(AnnotationMetadata metadata, DeferredImportSelector selector); /** * Return the {@link Entry entries} of which class(es) should be imported * for this group. */ Iterable<Entry> selectImports(); }

查看Group接口的实现类AutoConfigurationGroup中的selectImport,可追踪到类ConfigurationClassParser中的parse方法:
SpringBoot源码学习系列——自动配置原理(二)_第2张图片
进入parse方法,parse中直接调用了processConfigurationClass方法:
SpringBoot源码学习系列——自动配置原理(二)_第3张图片
进入doProcessConfigurationClass方法:
可以看到,依次对使用了@Component、@PropertySource、@ComponentScan、@Import、@ImportResource、@Bean的类、接口中的默认方法、配置类的父类进行处理
SpringBoot源码学习系列——自动配置原理(二)_第4张图片
SpringBoot源码学习系列——自动配置原理(二)_第5张图片
进入处理@Import的方法processImports
根据处理ImportSelector接口实现类的逻辑可以看出,如果实现了DeferredImportSelector接口,则为延迟导入,通过deferredImportSelectorHandler处理器进行处理,先加入集合,不会立即加载,这里即前文所述完成使用了@Configuration等注解的类加载后,再加载selectImports方法返回的指定的配置类,这里也不会去执行AutoConfigurationImportSelector类重写的selectImports方法,而如果只实现了ImportSelector接口,则递归解析,把解析到的类名按配置类直接完成加载,即在完成使用了@Configuration等注解的类加载前就进行了ImportSelector接口实现类的加载,从上面代码也可以看出,实际上只实现了ImportSelector接口的类,会在@ImportResource@Bean加载前完成加载

SpringBoot源码学习系列——自动配置原理(二)_第6张图片
继续进入deferredImportSelectorHandler#handle方法,生成了holder对象,存到了deferredImportSelectors中,这里只是将配置类存入了deferredImportSelectors,还没有加载配置类
SpringBoot源码学习系列——自动配置原理(二)_第7张图片
再来看下parse方法中this.deferredImportSelectorHandler.process()的处理逻辑:
SpringBoot源码学习系列——自动配置原理(二)_第8张图片进入register方法和processGroupImports方法:
SpringBoot源码学习系列——自动配置原理(二)_第9张图片
进入getImports,看到执行自定义的group#process方法
SpringBoot源码学习系列——自动配置原理(二)_第10张图片
process方法中执行了自动装配
SpringBoot源码学习系列——自动配置原理(二)_第11张图片

AutoConfigurationImportSelector

从上面分析过程也可以看出,自动配置时不会去执行AutoConfigurationImportSelector类重写的selectImports方法,而是通过自定义的group#process()完成,本质上还是通过AutoConfigurationImportSelector#getAutoConfigurationEntry获取待导入的bean,将自动配置类和被排除的类封装成了一个AutoConfigurationEntry对象,与AutoConfigurationImportSelector#selectImports类似
SpringBoot源码学习系列——自动配置原理(二)_第12张图片
下面是AutoConfigurationImportSelector#getAutoConfigurationEntry源码:

	protected AutoConfigurationEntry getAutoConfigurationEntry(AutoConfigurationMetadata autoConfigurationMetadata, AnnotationMetadata annotationMetadata) {
	    // 这步判断是否开启了自动配置,若未开启,返回空数组
		if (!isEnabled(annotationMetadata)) {
			return EMPTY_ENTRY;
		}
		// 获取注解的属性,此处返回key为 exclude和excludeName 的map
		AnnotationAttributes attributes = getAttributes(annotationMetadata);
		// 通过SpringFactoriesLoader.loadFactoryNames方法,获取spring.factories文件中所
		// 有需自动配置的类全名,即 org.springframework.boot.autoconfigure.XXXX
		List<String> configurations = getCandidateConfigurations(annotationMetadata, attributes);
		// 通过new ArrayList<>(new LinkedHashSet<>(list))实现配置类去重,同时保证了顺序
		configurations = removeDuplicates(configurations);
		// 获取被排除的类集合,包括前面attributes中exclude和excludeName中的类,
		// 和使用spring.autoconfigure.exclude指定的类
		Set<String> exclusions = getExclusions(annotationMetadata, attributes);
		// 通过ClassUtils.isPresent(exclusion, getClass().getClassLoader()) && !configurations.contains(exclusion)
		// 检查被排除的类能否实例化及是否属于自动配置类,若可实例化且不是自动配置类,则抛出异常
		checkExcludedClasses(configurations, exclusions);
		// 删去被排除的类
		configurations.removeAll(exclusions);
		// 检查配置类的注解是否满足spring.factories文件中
		// org.springframework.boot.autoconfigure.AutoConfigurationImportFilter
		// 指定的注解检查条件(OnBeanCondition,OnClassCondition,
		// OnWebApplicationCondition),筛选出满足的配置类
		configurations = filter(configurations, autoConfigurationMetadata);
		// 将配置类和被排除的类构建成AutoConfigurationImportEvent对象,传入监听器
		fireAutoConfigurationImportEvents(configurations, exclusions);
		return new AutoConfigurationEntry(configurations, exclusions);
	}

处理流程总结如下:

AutoConfigurationGroup的process方法中
执行getAutoConfigurationEntry获取自动配置类
Import注解启用AutoConfigurationImportSelector类
执行getAutoConfigurationMetadata方法完成metadata元数据加载
检查是否开启自动配置
加载自动配置类
去重
获取被排除配置类
检查被排除类是否合法
配置类集合中删除被排除的类
过滤自动加载组件
配置类和排除类通过event传入监听器
返回自动配置类及排除类对象

@EnableAutoConfiguration

下面对AutoConfigurationImportSelector#getAutoConfigurationEntry进行详细介绍

自动配置开关

  • isEnabled()
	protected boolean isEnabled(AnnotationMetadata metadata) {
	    // 这里会先判断是不是AutoConfigurationImportSelector类,若不是,默认返回true,即开启自动配置
	    // 若是AutoConfigurationImportSelector,则获取EnableAutoConfiguration.ENABLED_OVERRIDE_PROPERTY属性,即
	    // spring.boot.enableautoconfiguration,获取不到也默认返回true	     
		if (getClass() == AutoConfigurationImportSelector.class) {
			return getEnvironment().getProperty(EnableAutoConfiguration.ENABLED_OVERRIDE_PROPERTY, Boolean.class, true);
		}
		return true;
	}

加载元数据配置

可以看到,无论是AutoConfigurationImportSelector#selectImports中,还是自定义的AutoConfigurationGroup中,加载元数据都是通过AutoConfigurationMetadataLoader.loadMetadata完成SpringBoot源码学习系列——自动配置原理(二)_第13张图片
SpringBoot源码学习系列——自动配置原理(二)_第14张图片
AutoConfigurationMetadataLoader#loadMetadata
SpringBoot源码学习系列——自动配置原理(二)_第15张图片

	static AutoConfigurationMetadata loadMetadata(ClassLoader classLoader, String path) {
		try {
		    // 获取数据
			Enumeration<URL> urls = (classLoader != null) ? classLoader.getResources(path)
					: ClassLoader.getSystemResources(path);
			Properties properties = new Properties();
			// 将URL的属性存入properties
			while (urls.hasMoreElements()) {
				properties.putAll(PropertiesLoaderUtils.loadProperties(new UrlResource(urls.nextElement())));
			}
			// 封装properties,返回AutoConfigurationMetadata的实现类PropertiesAutoConfigurationMetadata对象 
			return loadMetadata(properties);
		}
		catch (IOException ex) {
			throw new IllegalArgumentException("Unable to load @ConditionalOnClass location [" + path + "]", ex);
		}
	}

这里去加载META-INF/spring-autoconfigure-metadata.properties文件,文件中配置如下:
自动配置类的全限定名.注解名=值
提前完成该数据的加载,可获取到所有配置类的各注解的值,也就拿到了@Conditional注解的值,在获取自动配置类时,根据条件删去不符合的配置类,这一方式减少了配置类的数量,也就减少了初始化Bean的时间,有效缩短了SpringBoot的启动时间。

加载自动配置类

自动配置类的获取通过以下三行代码完成
SpringBoot源码学习系列——自动配置原理(二)_第16张图片
AutoConfigurationImportSelector#getAttributes获取注解的属性map

	protected AnnotationAttributes getAttributes(AnnotationMetadata metadata) {
	    // getAnnotationClass()返回getAnnotationClass(),此处name即
	    // org.springframework.boot.autoconfigure.EnableAutoConfiguration
		String name = getAnnotationClass().getName();
		// 通过metadata.getAnnotationAttributes获取@EnableAutoConfiguration注解的属性,即exclude和excludeName
		// 返回一个AnnotationAttributes对象,本质是一个key为exclude和excludeName,值为对应属性值的LinkedHashMap
		AnnotationAttributes attributes = AnnotationAttributes.fromMap(metadata.getAnnotationAttributes(name, true));
		// 此处@EnableAutoConfiguration注解的属性不然不会是空,是空则异常
		Assert.notNull(attributes, () -> "No auto-configuration attributes found. Is " + metadata.getClassName()
				+ " annotated with " + ClassUtils.getShortName(name) + "?");
		return attributes;
	}

AutoConfigurationImportSelector#getCandidateConfigurations获取自动配置类

	protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {
	    // 如果configurations为空,会报错
	    // 参数getSpringFactoriesLoaderFactoryClass()返回值为EnableAutoConfiguration.class
	    // 此处只返回自动配置类
		List<String> configurations = SpringFactoriesLoader.loadFactoryNames(getSpringFactoriesLoaderFactoryClass(),
				getBeanClassLoader());
		Assert.notEmpty(configurations, "No auto configuration classes found in META-INF/spring.factories. If you "
				+ "are using a custom packaging, make sure that file is correct.");
		return configurations;
	}
    // 此处参数factoryType为EnableAutoConfiguration.class
	public static List<String> loadFactoryNames(Class<?> factoryType, @Nullable ClassLoader classLoader) {
		// 全类名org.springframework.boot.autoconfigure.EnableAutoConfiguration
		String factoryTypeName = factoryType.getName();
		return loadSpringFactories(classLoader).getOrDefault(factoryTypeName, Collections.emptyList());
	}
	private static Map<String, List<String>> loadSpringFactories(@Nullable ClassLoader classLoader) {
	    // MultiValueMap的value可以是list
		MultiValueMap<String, String> result = cache.get(classLoader);
		if (result != null) {
			return result;
		}

		try {
		    // FACTORIES_RESOURCE_LOCATION=META-INF/spring.factories
		    // 即获取META-INF/spring.factories文件,存到Enumeration
			Enumeration<URL> urls = (classLoader != null ?
					classLoader.getResources(FACTORIES_RESOURCE_LOCATION) :
					ClassLoader.getSystemResources(FACTORIES_RESOURCE_LOCATION));
			result = new LinkedMultiValueMap<>();
			while (urls.hasMoreElements()) {
				URL url = urls.nextElement();
				UrlResource resource = new UrlResource(url);
				// 返回Properties,实际是一个HashTable
				// 此处key、value对应spring.factories文件内容,添加到result中
				Properties properties = PropertiesLoaderUtils.loadProperties(resource);
				for (Map.Entry<?, ?> entry : properties.entrySet()) {
				    //这里的StringUtils.commaDelimitedListToStringArray将包含逗号的字符串按逗号分割后返回list
					String factoryTypeName = ((String) entry.getKey()).trim();
					for (String factoryImplementationName : StringUtils.commaDelimitedListToStringArray((String) entry.getValue())) {
						result.add(factoryTypeName, factoryImplementationName.trim());
					}
				}
			}
			cache.put(classLoader, result);
			// 返回值result是个LinkedMultiValueMap
			return result;
		}
		catch (IOException ex) {
			throw new IllegalArgumentException("Unable to load factories from location [" +
					FACTORIES_RESOURCE_LOCATION + "]", ex);
		}
	}

这是Map接口的getOrDefault方法,对前一步读取解析spring.factories得到的result进行处理,只获取key是org.springframework.boot.autoconfigure.EnableAutoConfiguration的配置类集合

    default V getOrDefault(Object key, V defaultValue) {
        // 如果map中包含该key或value不为空,返回对应value
        // 否则返回默认值
        V v;
        return (((v = get(key)) != null) || containsKey(key))
            ? v
            : defaultValue;
    }

AutoConfigurationImportSelector#removeDuplicates方法对前面得到的配置类集合进行了去重处理

	protected final <T> List<T> removeDuplicates(List<T> list) {
		return new ArrayList<>(new LinkedHashSet<>(list));
	}

可以看到,AutoConfigurationImportSelector#getCandidateConfigurations最终返回的是所需自动配置类的Map,key为org.springframework.boot.autoconfigure.EnableAutoConfiguration,值为自动配置类的list。

排除指定组件

下面对通过@EnableAutoConfiguration的注解属性excludeexcludeName、及配置文件指定spring.autoconfigure.exclude排除不需要自动配置的类的实现原理进行介绍,即下面三行代码。

SpringBoot源码学习系列——自动配置原理(二)_第17张图片
AutoConfigurationImportSelector#getExclusions:首先获取需要排除的类

	protected Set<String> getExclusions(AnnotationMetadata metadata, AnnotationAttributes attributes) {
		Set<String> excluded = new LinkedHashSet<>();
		// @EnableAutoConfiguration注解的exclude属性的值集合
		excluded.addAll(asList(attributes, "exclude"));
		// @EnableAutoConfiguration注解的excludeName属性的值集合
		excluded.addAll(Arrays.asList(attributes.getStringArray("excludeName")));
		// spring.autoconfigure.exclude配置项的值
		excluded.addAll(getExcludeAutoConfigurationsProperty());
		return excluded;
	}

AutoConfigurationImportSelector#checkExcludedClasses:检查被排除的类能否实例化及是否属于自动配置类,不满足任一点,异常

	private void checkExcludedClasses(List<String> configurations, Set<String> exclusions) {
		List<String> invalidExcludes = new ArrayList<>(exclusions.size());
		// 遍历指定的需排除的类
		for (String exclusion : exclusions) {
		    // ClassUtils.isPresent表示判断指定名称的类是否可实例化,此处即判断exclusion能否实例化
		    // 若exclusion可被实例化,且不属于自动配置类,则存入invalidExcludes
			if (ClassUtils.isPresent(exclusion, getClass().getClassLoader()) && !configurations.contains(exclusion)) {
				invalidExcludes.add(exclusion);
			}
		}
		// 若invalidExcludes不空,则进行异常处理
		if (!invalidExcludes.isEmpty()) {
			handleInvalidExcludes(invalidExcludes);
		}
	}
	protected void handleInvalidExcludes(List<String> invalidExcludes) {
		StringBuilder message = new StringBuilder();
		for (String exclude : invalidExcludes) {
			message.append("\t- ").append(exclude).append(String.format("%n"));
		}
		// 可以看到,抛出的异常为:以下类不是自动配置类,不能被排除
		throw new IllegalStateException(String.format(
				"The following classes could not be excluded because they are not auto-configuration classes:%n%s",
				message));
	}

得到被排除的类并完成检查后,通过removeAll方法从configurations集合中删去被排除的类

过滤自动配置组件

SpringBoot源码学习系列——自动配置原理(二)_第18张图片
下面对AutoConfigurationImportSelector#filter方法进行介绍:

    // 参数configurations为经过去重、排除指定类后的spring.factories文件中的自动配置类
    // 参数autoConfigurationMetadata为前面加载元数据步骤的结果,即从
    // META-INF/spring-autoconfigure-metadata.properties文件加载到的配置
	private List<String> filter(List<String> configurations, AutoConfigurationMetadata autoConfigurationMetadata) {
		long startTime = System.nanoTime();
		// configurations从list转出string数组
		String[] candidates = StringUtils.toStringArray(configurations);
		// 用于记录对应索引位置配置类是否需要满足spring-autoconfigure-metadata.properties文件中的配置条件
		boolean[] skip = new boolean[candidates.length];
		boolean skipped = false;
		// getAutoConfigurationImportFilters方法见下文,此处按照filter依次进行处理
		for (AutoConfigurationImportFilter filter : getAutoConfigurationImportFilters()) {
			invokeAwareMethods(filter);
			// 根据autoConfigurationMetadata中的条件配置处理candidates,true表示条件匹配成功
			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;
				}
			}
		}
		// 全部匹配成功,直接返回configurations
		if (!skipped) {
			return configurations;
		}
		List<String> result = new ArrayList<>(candidates.length);
		for (int i = 0; i < candidates.length; i++) {
		    // skip[i]为false,条件匹配成功,加入自动配置类结果集
			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);
	}

AutoConfigurationImportSelector#getAutoConfigurationImportFilters通过SpringFactoriesLoader#loadFactories方法获取spring.factories文件中key为org.springframework.boot.autoconfigure.AutoConfigurationImportFilter的属性值,即获取默认的filter类
# org.springframework.boot.autoconfigure.AutoConfigurationImportFilter=\ org.springframework.boot.autoconfigure.condition.OnBeanCondition,\ org.springframework.boot.autoconfigure.condition.OnClassCondition,\ org.springframework.boot.autoconfigure.condition.OnWebApplicationCondition
在这里插入图片描述
SpringBoot源码学习系列——自动配置原理(二)_第19张图片

FilteringSpringBootCondition#match方法:

	@Override
	public boolean[] match(String[] autoConfigurationClasses, AutoConfigurationMetadata autoConfigurationMetadata) {
		ConditionEvaluationReport report = ConditionEvaluationReport.find(this.beanFactory);
		// 判断条件是否匹配核心方法,由FilteringSpringBootCondition类的三个子类分别实现
		ConditionOutcome[] outcomes = getOutcomes(autoConfigurationClasses, autoConfigurationMetadata);
		// 下面将getOutcomes返回的结果转换成boolean数组
		boolean[] match = new boolean[outcomes.length];
		for (int i = 0; i < outcomes.length; i++) {
		    // outcomes[i]为空或isMatch()为true都表示条件匹配成功,match[i]取true,这点从下文的分析可以得出
			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方法实现,以OnClassCondition子类实现为例进行说明:

	@Override
	protected final ConditionOutcome[] getOutcomes(String[] autoConfigurationClasses,
			AutoConfigurationMetadata autoConfigurationMetadata) {
		// Split the work and perform half in a background thread if more than one
		// processor is available. Using a single additional thread seems to offer the
		// best performance. More threads make things worse.
		if (Runtime.getRuntime().availableProcessors() > 1) {
		    // 处理器为多个,采用后台线程处理,通过分半处理提升效率,本质还是
		    // 通过StandardOutcomesResolver#resolveOutcomes实现
			return resolveOutcomesThreaded(autoConfigurationClasses, autoConfigurationMetadata);
		}
		else {
			OutcomesResolver outcomesResolver = new StandardOutcomesResolver(autoConfigurationClasses, 0,
					autoConfigurationClasses.length, autoConfigurationMetadata, getBeanClassLoader());
			return outcomesResolver.resolveOutcomes();
		}
	}

OnClassCondition#resolveOutcomesThreaded
SpringBoot源码学习系列——自动配置原理(二)_第20张图片
此处继续进入createOutcomesResolver方法,可以看到new了一个ThreadedOutcomesResolver对象
SpringBoot源码学习系列——自动配置原理(二)_第21张图片
在这里插入图片描述
分半后进行处理时,先处理了普通的StandardOutcomesResolver对象,然后处理ThreadedOutcomesResolver对象,这两个类对resolveOutcomes方法实现不同,普通的StandardOutcomesResolver对象直接调用OnClassCondition#resolveOutcomesThreadedOutcomesResolver对象则通过this.thread.join();使得主线程阻塞,等待ThreadedOutcomesResolver对象中子线程处理结束后才继续主线程后续处理逻辑。

OnClassCondition#resolveOutcomes
在这里插入图片描述
OnClassCondition#getOutcomes

		private ConditionOutcome[] getOutcomes(String[] autoConfigurationClasses, int start, int end,
				AutoConfigurationMetadata autoConfigurationMetadata) {
		    // 初始化outcomes存放结果
			ConditionOutcome[] outcomes = new ConditionOutcome[end - start];
			for (int i = start; i < end; i++) {
			    // 获取当前处理的自动配置类,例如
			    // org.springframework.boot.autoconfigure.jms.JndiConnectionFactoryAutoConfiguration
				String autoConfigurationClass = autoConfigurationClasses[i];
				if (autoConfigurationClass != null) {
				    // 执行AutoConfigurationMetadataLoader#get方法
				    // 获取元数据即spring-autoconfigure-metadata.properties中key为
				    // org.springframework.boot.autoconfigure.jms.JndiConnectionFactoryAutoConfiguration.ConditionalOnClass   
				    // 的属性值,即key为自动配置类名+ConditionalOnClass的属性值,也就是该配置类加载的条件
				    // 以此为例,条件value为org.springframework.jms.core.JmsTemplate
					String candidates = autoConfigurationMetadata.get(autoConfigurationClass, "ConditionalOnClass");
					// 存在加载条件,则进行判断,核心为getOutcome方法
					if (candidates != null) {
						outcomes[i - start] = getOutcome(candidates);
					}
				}
			}
			return outcomes;
		}
		private ConditionOutcome getOutcome(String className, ClassLoader classLoader) {
		    // ClassNameFilter.MISSING是FilteringSpringBootCondition的一个枚举类的属性,调用其内部方法matches
			if (ClassNameFilter.MISSING.matches(className, classLoader)) {
				return ConditionOutcome.noMatch(ConditionMessage.forCondition(ConditionalOnClass.class)
						.didNotFind("required class").items(Style.QUOTE, className));
			}
			return null;
		}

org.springframework.boot.autoconfigure.jms.JndiConnectionFactoryAutoConfiguration为例,返回的结果如下
在这里插入图片描述

SpringBoot源码学习系列——自动配置原理(二)_第22张图片

		static boolean isPresent(String className, ClassLoader classLoader) {
			if (classLoader == null) {
				classLoader = ClassUtils.getDefaultClassLoader();
			}
			try {
				resolve(className, classLoader);
				return true;
			}
			catch (Throwable ex) {
				return false;
			}
		}
    // 可以看到,即判断当前className能否当前类加载器加载,可以加载则匹配成功,否则匹配失败
	protected static Class<?> resolve(String className, ClassLoader classLoader) throws ClassNotFoundException {
		if (classLoader != null) {
			return classLoader.loadClass(className);
		}
		return Class.forName(className);
	}

到此,对过滤自动配置的分析就结束了,大致流程可总结如下:

获取spring.factories中的过滤器
遍历执行filter的match方法
根据自动配置类名和注解名获取元数据配置中的条件类
用类加载器加载该条件类,加载成功则匹配成功,否则不匹配,就需要排除
返回匹配结果数组
获取满足条件的自动配置类集合

事件注册

AutoConfigurationImportSelector#fireAutoConfigurationImportEvents

	private void fireAutoConfigurationImportEvents(List<String> configurations, Set<String> exclusions) {
	    // 通过SpringFactoriesLoader.loadFactories获取spring.factories中配置的Listener
		List<AutoConfigurationImportListener> listeners = getAutoConfigurationImportListeners();
		if (!listeners.isEmpty()) {
		    // 将configurations和exclusions封装成event事件后,传入监听器
			AutoConfigurationImportEvent event = new AutoConfigurationImportEvent(this, configurations, exclusions);
			for (AutoConfigurationImportListener listener : listeners) {
				invokeAwareMethods(listener);
				listener.onAutoConfigurationImportEvent(event);
			}
		}
	}

    // 获取spring.factories中属性
    // org.springframework.boot.autoconfigure.AutoConfigurationImportListener
    // 的值
	protected List<AutoConfigurationImportListener> getAutoConfigurationImportListeners() {
		return SpringFactoriesLoader.loadFactories(AutoConfigurationImportListener.class, this.beanClassLoader);
	}

你可能感兴趣的:(spring,boot,学习,java)