关联博文:
SpringBoot自动配置原理解析(一)
SpringBoot自动配置原理解析(二)
SpringBoot自动配置原理解析(三)
SpringBoot自动配置原理解析(四)
SpringBoot自动配置原理解析(五)
接上文SpringBoot自动配置原理解析(二)我们继续往下分析。
如下是ConfigurationClassParser
的parse
方法,当内部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
DeferredImportSelectorHandler
是ConfigurationClassParser
的内部类,维护了一个成员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());
}
方法如上所示,首先得到ImportSelector
的ImportGroup
,本文这里得到的是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方法是核心。我们继续看DeferredImportSelectorGroupingHandler
的processGroupImports
方法。首先遍历触发每个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.AutoConfigurationGroup
的getAutoConfigurationMetadata
方法会实例化得到一个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);
这个方法。
这里来到了AutoConfigurationImportSelector
的getCandidateConfigurations
,很明了,从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,我们继续回到DeferredImportSelectorGrouping
的getImports
方法,接下来分析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
进行判断循环处理。