关联博文:
接上文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
进行判断循环处理。