SpringBoot自动配置原理解析(三)

关联博文:
SpringBoot自动配置原理解析(一)
SpringBoot自动配置原理解析(二)
SpringBoot自动配置原理解析(三)
SpringBoot自动配置原理解析(四)
SpringBoot自动配置原理解析(五)

接上文SpringBoot自动配置原理解析(二)我们继续往下分析。

如下是ConfigurationClassParserparse方法,当内部parse方法执行完后,就该执行this.deferredImportSelectorHandler.process();方法。这个时候我们的@Bean方法还只是configClass中的BeanMethod,还没有被注册为BeanDefinition。

public void parse(Set<BeanDefinitionHolder> configCandidates) {
	for (BeanDefinitionHolder holder : configCandidates) {
		BeanDefinition bd = holder.getBeanDefinition();
		try {
			if (bd instanceof AnnotatedBeanDefinition) {
				parse(((AnnotatedBeanDefinition) bd).getMetadata(), holder.getBeanName());
			}
			else if (bd instanceof AbstractBeanDefinition && ((AbstractBeanDefinition) bd).hasBeanClass()) {
				parse(((AbstractBeanDefinition) bd).getBeanClass(), holder.getBeanName());
			}
			else {
				parse(bd.getBeanClassName(), holder.getBeanName());
			}
		}
		//...两个catch
	}

	this.deferredImportSelectorHandler.process();
}

我们来看看deferredImportSelectorHandler的process方法。

【1】DeferredImportSelectorHandler

DeferredImportSelectorHandlerConfigurationClassParser的内部类,维护了一个成员deferredImportSelectors 存储DeferredImportSelectorHolder

private List<DeferredImportSelectorHolder> deferredImportSelectors = new ArrayList<>();

前文我们看到了,我们AutoConfigurationImportSelector被实例化为DeferredImportSelectorHolder放到了deferredImportSelectors 中。
在这里插入图片描述
前面我们触发的是其handle方法,这里我们看下其process方法。

public void process() {
// 做一下置换,将deferredImportSelectors 赋予null
	List<DeferredImportSelectorHolder> deferredImports = this.deferredImportSelectors;
	this.deferredImportSelectors = null;
	try {
		if (deferredImports != null) {
		//实例化DeferredImportSelectorGroupingHandler 
			DeferredImportSelectorGroupingHandler handler = new DeferredImportSelectorGroupingHandler();
			// 排序
			deferredImports.sort(DEFERRED_IMPORT_COMPARATOR);

			//对每一个DeferredImportSelectorHolder触发
			//DeferredImportSelectorGroupingHandler 的register方法
			deferredImports.forEach(handler::register);
			
			// 这里是核心
			handler.processGroupImports();
		}
	}
	finally {
		this.deferredImportSelectors = new ArrayList<>();
	}
}

这里有两个方法需要我们注意,分别是register和processGroupImports。我们首先看一下deferredImports.forEach(handler::register);

① register

这里核心就是对List<DeferredImportSelectorHolder> deferredImports进行分组放到groupings中,并将所属configClass放到configurationClasses中。

// ConfigurationClassParser.DeferredImportSelectorGroupingHandler#register
public void register(DeferredImportSelectorHolder deferredImport) {

// 本文这里获取的group是AutoConfigurationImportSelector$AutoConfigurationGroup
	Class<? extends Group> group = deferredImport.getImportSelector()
			.getImportGroup();
//放入groupings并将value返回
	DeferredImportSelectorGrouping grouping = this.groupings.computeIfAbsent(
			(group != null ? group : deferredImport),
			key -> new DeferredImportSelectorGrouping(createGroup(group)));
	grouping.add(deferredImport);

//放入configurationClasses中
	this.configurationClasses.put(deferredImport.getConfigurationClass().getMetadata(),
			deferredImport.getConfigurationClass());
}

方法如上所示,首先得到ImportSelectorImportGroup,本文这里得到的是AutoConfigurationImportSelector$AutoConfigurationGroup

然后根据group 得到grouping ,将当前DeferredImportSelectorHolder deferredImport放到grouping 中。

本文这里的deferredImport如下所示,其包含了所属configClass和引入的AutoConfigurationImportSelector。
在这里插入图片描述
当前this中groupings如下所示:
在这里插入图片描述
当前this中configurationClasses如下所示:
在这里插入图片描述

注意,这里的this指的是DeferredImportSelectorGroupingHandler。如下所示,DeferredImportSelectorGroupingHandler维护了两个Map。

private final Map<Object, DeferredImportSelectorGrouping> groupings = new LinkedHashMap<>();

private final Map<AnnotationMetadata, ConfigurationClass> configurationClasses = new HashMap<>();

② processGroupImports

register方法可以跳过,但是这个processGroupImports方法是核心。我们继续看DeferredImportSelectorGroupingHandlerprocessGroupImports方法。首先遍历触发每个grouping的getImports方法然后遍历触发processImports方法。当然本文这里我们只有一个分组就是AutoConfigurationGroup。

public void processGroupImports() {
	for (DeferredImportSelectorGrouping grouping : this.groupings.values()) {
	//本文我们得到的候选配置有45个
		grouping.getImports().forEach(entry -> {
			ConfigurationClass configurationClass = this.configurationClasses.get(
					entry.getMetadata());
			try {
			// 这里先说一下,执行完这个方法后候选配置有244个
			// 我们从spring.factories得到的配置类在这个processImports中被处理
				processImports(configurationClass, asSourceClass(configurationClass),
						asSourceClasses(entry.getImportClassName()), false);
			}
			//...一堆catch
		});
	}
}

entry里面存放的是什么呢?如下图所示:
在这里插入图片描述

processImports方法就是前文我们分析过的那个processImports方法。这里我们可以简单说一下,当我们获取到那些配置类比如MessageSourceAutoConfiguration时,这里会触发下面这行代码。

processImports(configurationClass, asSourceClass(configurationClass),
						asSourceClasses(entry.getImportClassName()), false);

唯一需要注意的是asSourceClasses(entry.getImportClassName())其实也就是说我们的XXXXAutoConfiguration会被作为候选导入类Collection<SourceClass> importCandidates扔给processImports方法。前文我们提到过importCandidates是可以被作为配置类触发解析过程的,也是可以在reader.loadBeanDefinitions过程中被注册为BeanDefinition的。

有同学可能好奇,configurationClass是什么?如下图所示这里是我们的主启动类。

在这里插入图片描述

ok,接下来我们看一下getImports方法。这里触发的是DeferredImportSelectorGrouping 的getImports方法。

【2】DeferredImportSelectorGrouping

DeferredImportSelectorGrouping 如下所示,内部维护了group和与group相关的List<DeferredImportSelectorHolder> deferredImports

private static class DeferredImportSelectorGrouping {
//维护了group
	private final DeferredImportSelector.Group group;

//维护了集合deferredImports 
	private final List<DeferredImportSelectorHolder> deferredImports = new ArrayList<>();

	DeferredImportSelectorGrouping(Group group) {
		this.group = group;
	}
//提供了add方法
	public void add(DeferredImportSelectorHolder deferredImport) {
		this.deferredImports.add(deferredImport);
	}

	/**
	 * Return the imports defined by the group.
	 * @return each import with its associated configuration class
	 */
	 // 对deferredImports进行遍历,对group触发其process方法
	public Iterable<Group.Entry> getImports() {
		for (DeferredImportSelectorHolder deferredImport : this.deferredImports) {
			this.group.process(deferredImport.getConfigurationClass().getMetadata(),
					deferredImport.getImportSelector());
		}
		// 触发group的selectImports方法
		return this.group.selectImports();
	}
}

前面我们提到了,这里group就是我们的AutoConfigurationGroup。下面我们分析process()selectImports()方法。

① process

这里触发的是AutoConfigurationGroup的process方法。

// .AutoConfigurationImportSelector.AutoConfigurationGroup#process
@Override
public void process(AnnotationMetadata annotationMetadata, DeferredImportSelector deferredImportSelector) {
	//...省略一个Assert.state,下面这句话是核心
	AutoConfigurationEntry autoConfigurationEntry = ((AutoConfigurationImportSelector) deferredImportSelector)
			.getAutoConfigurationEntry(getAutoConfigurationMetadata(), annotationMetadata);

//将得到autoConfigurationEntry放入ArrayList autoConfigurationEntries中
	this.autoConfigurationEntries.add(autoConfigurationEntry);

//遍历放入Map<String, AnnotationMetadata> entries = new LinkedHashMap<>()
	for (String importClassName : autoConfigurationEntry.getConfigurations()) {
		this.entries.putIfAbsent(importClassName, annotationMetadata);
	}
}

getAutoConfigurationMetadata()

首先触发getAutoConfigurationMetadata()方法,用来获取AutoConfigurationMetadata 。

AutoConfigurationImportSelector.AutoConfigurationGroupgetAutoConfigurationMetadata方法会实例化得到一个AutoConfigurationMetadata autoConfigurationMetadata

其将会搜索并加载META-INF/spring-autoconfigure-metadata.properties配置信息得到其Properties然后根据Properties实例化得到PropertiesAutoConfigurationMetadata对象。

(1.2)核心方法getAutoConfigurationEntry

// AutoConfigurationImportSelector#getAutoConfigurationEntry
protected AutoConfigurationEntry getAutoConfigurationEntry(AutoConfigurationMetadata autoConfigurationMetadata,
		AnnotationMetadata annotationMetadata) {

// 如果环境配置了spring.boot.enableautoconfiguration为false,则直接返回
	if (!isEnabled(annotationMetadata)) {
		return EMPTY_ENTRY;
	}
	// 得到注解的属性
	AnnotationAttributes attributes = getAttributes(annotationMetadata);
	//获取候选配置类
	List<String> configurations = getCandidateConfigurations(annotationMetadata, attributes);
	//移除重复的
	configurations = removeDuplicates(configurations);
	//获取配置的排除信息并从configurations移除排除的
	Set<String> exclusions = getExclusions(annotationMetadata, attributes);
	checkExcludedClasses(configurations, exclusions);
	configurations.removeAll(exclusions);
	//过滤configurations
	configurations = filter(configurations, autoConfigurationMetadata);

	// 触发AutoConfigurationImportListener监听的onAutoConfigurationImportEvent方法
	//可以简单理解为AutoConfigurationImportEvent事件被相应的监听器处理
	fireAutoConfigurationImportEvents(configurations, exclusions);
	
	//返回AutoConfigurationEntry
	return new AutoConfigurationEntry(configurations, exclusions);
}

方法流程梳理如下

  • 如果环境配置了spring.boot.enableautoconfiguration为false,则直接返回
  • 得到注解的属性
  • 获取候选配置类–核心方法
  • 移除重复的
  • 获取配置的排除信息并从configurations移除排除的
  • 过滤configurations
  • 触发AutoConfigurationImportListener监听的onAutoConfigurationImportEvent方法,可以简单理解为AutoConfigurationImportEvent事件被相应的监听器处理
  • 返回AutoConfigurationEntry

那么如何得到候选配置类?我们继续追踪getCandidateConfigurations(annotationMetadata, attributes);这个方法。

这里来到了AutoConfigurationImportSelectorgetCandidateConfigurations,很明了,从META-INF/spring.factories检索EnableAutoConfiguration配置信息!!

// AutoConfigurationImportSelector#getCandidateConfigurations
protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {
// 从META-INF/spring.factories检索EnableAutoConfiguration配置信息
	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;
}

protected Class<?> getSpringFactoriesLoaderFactoryClass() {
	return EnableAutoConfiguration.class;
}

这里得到的configurations如下所示,有130个:
在这里插入图片描述

如何过滤configurations呢?这里会从环境中检索AutoConfigurationImportFilter使用得到的Filter进行过滤。

protected List<AutoConfigurationImportFilter> getAutoConfigurationImportFilters() {
	return SpringFactoriesLoader.loadFactories(AutoConfigurationImportFilter.class, this.beanClassLoader);
}
// META-INF/spring.factories配置的AutoConfigurationImportFilter如下
org.springframework.boot.autoconfigure.AutoConfigurationImportFilter=\
org.springframework.boot.autoconfigure.condition.OnBeanCondition,\
org.springframework.boot.autoconfigure.condition.OnClassCondition,\
org.springframework.boot.autoconfigure.condition.OnWebApplicationCondition

如下所示,过滤完这里本文这里还剩下45个:
在这里插入图片描述

OK,我们继续回到DeferredImportSelectorGroupinggetImports方法,接下来分析selectImports方法。

② selectImports

AutoConfigurationImportSelector.AutoConfigurationGroup的selectImports方法。就是对autoConfigurationEntries维护的配置类进行了整体筛选然后排序然后映射得到一个List。

public Iterable<Entry> selectImports() {
	if (this.autoConfigurationEntries.isEmpty()) {
		return Collections.emptyList();
	}
	// 获取到所有的排他配置
	Set<String> allExclusions = this.autoConfigurationEntries.stream()
			.map(AutoConfigurationEntry::getExclusions).flatMap(Collection::stream).collect(Collectors.toSet());

// 获取到autoConfigurationEntries中所有配置类
	Set<String> processedConfigurations = this.autoConfigurationEntries.stream()
			.map(AutoConfigurationEntry::getConfigurations).flatMap(Collection::stream)
			.collect(Collectors.toCollection(LinkedHashSet::new));

// 从中移除排他配置
	processedConfigurations.removeAll(allExclusions);

//排序 然后映射得到Entry这样一个List
	return sortAutoConfigurations(processedConfigurations, getAutoConfigurationMetadata()).stream()
			.map((importClassName) -> new Entry(this.entries.get(importClassName), importClassName))
			.collect(Collectors.toList());
}

当执行完所有的候选配置类后,也就是对我们从META-INF\spring.factories加载并过滤后的配置类执行完processImports方法后,来到了this.deferredImportSelectors = new ArrayList<>();,这时我们解析器里面的候选配置类有244个了!
在这里插入图片描述

得到一个entry 的集合后就开始遍历对每一个entry 触发processImports方法。

grouping.getImports().forEach(entry -> {
	ConfigurationClass configurationClass = this.configurationClasses.get(
			entry.getMetadata());
	try {
	// 这里先说一下,执行完这个方法后候选配置有244个
	// 我们从spring.factories得到的配置类在这个processImports中被处理
		processImports(configurationClass, asSourceClass(configurationClass),
				asSourceClasses(entry.getImportClassName()), false);
}

接下来就该ConfigurationClassBeanDefinitionReader使用加载BeanDefinition了,然后将registry.getBeanDefinitionCount() > candidateNames.length进行判断循环处理。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

流烟默

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值