DeferredImportSelector的处理
一、Spring处理配置类大致过程
回忆一下Spring处理配置类的大致过程【ConfigurationClassPostProcessor】
【BeanFactoryPostProcessor -> BeanDefinitionRegistryPostProcessor】 ConfigurationClassPostProcessor#postProcessBeanDefinitionRegistry -> ConfigurationClassPostProcessor#processConfigBeanDefinitions -> ConfigurationClassParser#parse(Set<BeanDefinitionHolder>) 开始解析配置传入的配置类 ConfigurationClassParser#parse(Set<BeanDefinitionHolder>) - #parse(AnnotationMetadata, String) [最后调用 deferredImportSelectorHandler.process] - #processConfigurationClass [@Import导入的非三个特殊接口的类递归调用此方法处理], [调用此方法处理的配置类都放入 configurationClasses 字段] - #doProcessConfigurationClass - #processImports @Component扫描出来的递归调用ConfigurationClassParser#parse(String, String)处理 - #processConfigurationClass 进而调用它, 回到上面的步骤
二、@Import大致处理过程
直接看@Import的处理过程
protected final SourceClass doProcessConfigurationClass( ConfigurationClass configClass, SourceClass sourceClass, Predicate<String> filter) throws IOException { // 使用了@Component注解, ... // Process any @PropertySource annotations, .... // Process any @ComponentScan annotations, ... // Process any 【@Import】 annotations processImports(configClass, sourceClass, getImports(sourceClass), filter, true); // Process any @ImportResource annotations, ... // Process individual @Bean methods // 处理@Bean,获取所有 @Bean 方法,还没有到代理的逻辑, .... // 处理继承的接口中的使用@Bean修饰的deafult方法 processInterfaces(configClass, sourceClass); // Process superclass, if any, ... // 没有父类 return null; } private void processImports(ConfigurationClass configClass, SourceClass currentSourceClass, Collection<SourceClass> importCandidates, Predicate<String> exclusionFilter, boolean checkForCircularImports) { // 没有Import任何东西,则仅表示此类是一个配置类 if (importCandidates.isEmpty()) { return; } // 循环注入的检查 if (checkForCircularImports && isChainedImportOnStack(configClass)) { // 报错 this.problemReporter.error(new CircularImportProblem(configClass, this.importStack)); } else { // importStack 好像是整个解析过程中全局的, importStack 干什么的呢 this.importStack.push(configClass); try { // 遍历所有被@Import引入的类 for (SourceClass candidate : importCandidates) { // 如果继承了【ImportSelector】接口 if (candidate.isAssignable(ImportSelector.class)) { // Candidate class is an ImportSelector -> delegate to it to determine imports // 让这个被Import引入的类决定实际引入那些类 Class<?> candidateClass = candidate.loadClass(); // 实例化 ImportSelector selector = ParserStrategyUtils.instantiateClass(candidateClass, ImportSelector.class, this.environment, this.resourceLoader, this.registry); Predicate<String> selectorFilter = selector.getExclusionFilter(); if (selectorFilter != null) { exclusionFilter = exclusionFilter.or(selectorFilter); } // 如果是继承了 DeferredImportSelector 接口 if (selector instanceof DeferredImportSelector) { // 延迟引入,在所有的@Configuration处理完毕后处理,在作为@Conditional条件@Import时特别有用 // 这个应该不可以继续@Import this.deferredImportSelectorHandler.handle(configClass, (DeferredImportSelector) selector); } else { // 返回的是字符串全类名 String[] importClassNames = selector.selectImports(currentSourceClass.getMetadata()); Collection<SourceClass> importSourceClasses = asSourceClasses(importClassNames, exclusionFilter); // 被当作直接@Import的数组再处理,也即可以继续@Import processImports(configClass, currentSourceClass, importSourceClasses, exclusionFilter, false); } } // 如果继承ImportBeanDefinitionRegistrar接口,主要是作为在处理@Configuration的过程中添加BD,需要在BD级别自定义一个Bean时有用 else if (candidate.isAssignable(ImportBeanDefinitionRegistrar.class)) { // Candidate class is an ImportBeanDefinitionRegistrar -> // delegate to it to register additional bean definitions // 由@Import的实例自行定义BD,上面的两个都是由Spring帮助定义BD Class<?> candidateClass = candidate.loadClass(); ImportBeanDefinitionRegistrar registrar = ParserStrategyUtils.instantiateClass(candidateClass, ImportBeanDefinitionRegistrar.class, this.environment, this.resourceLoader, this.registry); // 没有注入BD,什么时候调用 // 放入了ConfigClass中 configClass.addImportBeanDefinitionRegistrar(registrar, currentSourceClass.getMetadata()); } else { // Candidate class not an ImportSelector or ImportBeanDefinitionRegistrar -> // process it as an @Configuration class // 其他被@Import的类,被当作配置类进行处理 // 注意这里和扫描出来的有区别,扫描出来的是立即注入BD,然后如果是配置类再解析 // 而@Import暂时不注入,当作配置类解析,但是 processConfigurationClass 调用后被放在字段 configurationClasses 中 this.importStack.registerImport( currentSourceClass.getMetadata(), candidate.getMetadata().getClassName()); processConfigurationClass(candidate.asConfigClass(configClass), exclusionFilter); } } } catch (BeanDefinitionStoreException ex) { throw ex; } catch (Throwable ex) { throw new BeanDefinitionStoreException( "Failed to process import candidates for configuration class [" + configClass.getMetadata().getClassName() + "]", ex); } finally { this.importStack.pop(); } } }
@Import区分了三种类
- 继承了ImportSelector接口的类,直接实例化这个类,调用selectImports将返回的类全限定名数组当做配置类处理,注意这个类不被注入容器
- 继承了DeferredImportSelector接口(ImportSelector子接口)的类,暂时未处理,可以看到后面处理后也是讲返回的类全部调用processImports当做被直接@Import的处理
- 继承了ImportBeanDefinitionRegistrar接口的类,暂时未处理,【用于自定义BD注入】
- 普通类,当做配置类进行解析
三、DeferredImportSelector接口处理
看DeferredImportSelector接口的处理
注意前面processImports时已经将@Import进入的DeferredImportSelector接口的类this.deferredImportSelectorHandler.handle(configClass, (DeferredImportSelector) selector)添加了
// deferredImportSelectorHandler 为 ConfigurationClassParser 的全局字段 // 实际上就是存储起来, 暂时不调用 this.deferredImportSelectorHandler.handle(configClass, (DeferredImportSelector) selector); private class DeferredImportSelectorHandler { private List<DeferredImportSelectorHolder> deferredImportSelectors = new ArrayList<>(); // @Import 遇到 DeferredImportSelectorHolder 先不处理, 调用它存储起来 public void handle(ConfigurationClass configClass, DeferredImportSelector importSelector) { // 包装 configClass 和 importSelector 实例, 前者配置类, 后者被配置类 @Import 的 DeferredImportSelector DeferredImportSelectorHolder holder = new DeferredImportSelectorHolder(configClass, importSelector); // process后才为null,process后的其他直接进行处理 // 什么时候会为 null ? 为 null 的时候应该是见一个立即处理一个, 否则存储起来等待一起被调用处理 if (this.deferredImportSelectors == null) { DeferredImportSelectorGroupingHandler handler = new DeferredImportSelectorGroupingHandler(); handler.register(holder); handler.processGroupImports(); } else { // List#add this.deferredImportSelectors.add(holder); } } }
DeferredImportSelectorHolder的定义较为简单,仅封装两个字段,相当于Pair,就不列出来了
接着等待被处理,什么时候处理呢?看最开始列出的流程,在刚进入的第一个方法parse最后处理,此时parse的这些配置类已被处理完毕,【这些配置类仅是ConfigurationClassPostProcessor第一次找到的所有配置类,待续】
ConfigurationClassPostProcessor#processConfigBeanDefinitions --> public void ConfigurationClassParser.parse(Set<BeanDefinitionHolder> configCandidates) { // 内部都是配置类,都需要进行解析 for (BeanDefinitionHolder holder : configCandidates) { BeanDefinition bd = holder.getBeanDefinition(); try { // 注解BD,只看这个即可 if (bd instanceof AnnotatedBeanDefinition) { parse(((AnnotatedBeanDefinition) bd).getMetadata(), holder.getBeanName()); } // ... } } // 这里处理 DeferredImportSelector this.deferredImportSelectorHandler.process(); }
DeferredImportSelectorHandler的其余代码,前面注册的handle已列出
class ConfigurationClassParser{ private class DeferredImportSelectorHandler { @Nullable private List<DeferredImportSelectorHolder> deferredImportSelectors = new ArrayList<>(); public void process() { // 所有的 DeferredImportSelector List<DeferredImportSelectorHolder> deferredImports = this.deferredImportSelectors; // 清空, handler的那个null判断处理难道是防止多线程问题??? this.deferredImportSelectors = null; try { if (deferredImports != null) { DeferredImportSelectorGroupingHandler handler = new DeferredImportSelectorGroupingHandler(); // DeferredImportSelectorHolder 排序 deferredImports.sort(DEFERRED_IMPORT_COMPARATOR); // 遍历, 调用 DeferredImportSelectorGroupingHandler#register 处理 // 注册, 对每一个进行注册 deferredImports.forEach(handler::register); // 实际处理, 批量处理 handler.processGroupImports(); } } finally { this.deferredImportSelectors = new ArrayList<>(); } } } private class DeferredImportSelectorGroupingHandler { /** * 键 DeferredImportSelector.Group(可能返回null, null则后面) 或 DeferredImportSelector * 值:DeferredImportSelectorGrouping */ private final Map<Object, DeferredImportSelectorGrouping> groupings = new LinkedHashMap<>(); private final Map<AnnotationMetadata, ConfigurationClass> configurationClasses = new HashMap<>(); // 处理 DeferredImportSelector // 这里仅注册 public void register(DeferredImportSelectorHolder deferredImport) { // DeferredImportSelectorHolder#getImportSelector 得到 DeferredImportSelectorHolder // 然后 DeferredImportSelectorHolder#getImportGroup, 注意是一个 Class Class<? extends Group> group = deferredImport.getImportSelector().getImportGroup(); // 键: DeferredImportSelector.Group 或 为null时使用 DeferredImportSelector // 值: DeferredImportSelectorGrouping DeferredImportSelectorGrouping grouping = this.groupings.computeIfAbsent( (group != null ? group : deferredImport), // createGroup 创建Group实现类对象并对部分Aware接口进行了回调, 当为null使用 DefaultDeferredImportSelectorGroup key -> new DeferredImportSelectorGrouping(createGroup(group))); // 所有 DeferredImportSelectorHolder // grouping 然后添加 DeferredImportSelectorHolder 实例, 可绑定多个 // 相当于 Map<Group, List> grouping.add(deferredImport); // 所有configuration this.configurationClasses.put(deferredImport.getConfigurationClass().getMetadata(), deferredImport.getConfigurationClass()); } // 实际处理 public void processGroupImports() { // 相当于 grouping 为一个 List<DeferredImportSelectorGrouping>, 每个DeferredImportSelectorGrouping含多个Group实例 for (DeferredImportSelectorGrouping grouping : this.groupings.values()) { Predicate<String> exclusionFilter = grouping.getCandidateFilter(); // DeferredImportSelectorGrouping#getImports 会使用一个 Group 实例对多个 DeferredImportSelector 进行处理 // -- 先 forEach -> Group#process(DeferredImportSelector) 一般对每一个DeferredImportSelector能得到此Selector要注入的信息, Group会自己缓存起来 // -- 再 Group#selectImports 总的处理, 返回 Iterable<Entry>, Entry保存着要导入的类和导入此类的配置类的注解信息 grouping.getImports().forEach(entry -> { // 对每一个 Entry 进行处理 // 得到配置类实例 ConfigurationClass configurationClass = this.configurationClasses.get(entry.getMetadata()); try { // !!! 再次processImports, 也就是把要注入的这个类当做 configurationClass 使用 @Import 注入时处理 @Import // 因此还会对这个注入的类进行 @Import 接口处理、配置处理等等 // 不过此时的这个被导入的类使用 DeferredImportSelector、ImportBeanDefinitionRegistrar 接口还有作用吗 // 倒是可以导入ImportSelector接口的和其他类型配置类(因为会被当做配置类解析一遍) processImports(configurationClass, asSourceClass(configurationClass, exclusionFilter), Collections.singleton(asSourceClass(entry.getImportClassName(), exclusionFilter)), exclusionFilter, false); } catch (BeanDefinitionStoreException ex) { throw ex; } catch (Throwable ex) { throw new BeanDefinitionStoreException( "Failed to process import candidates for configuration class [" + configurationClass.getMetadata().getClassName() + "]", ex); } }); } } /** * 创建对象,对部分Aware接口进行了回调,应该是还没到Bean生命周期处理周期就需要使用到 */ private Group createGroup(@Nullable Class<? extends Group> type) { Class<? extends Group> effectiveType = (type != null ? type : DefaultDeferredImportSelectorGroup.class); return ParserStrategyUtils.instantiateClass(effectiveType, Group.class, ConfigurationClassParser.this.environment, ConfigurationClassParser.this.resourceLoader, ConfigurationClassParser.this.registry); } } }
- 一般来说在ConfigurationClassParser#parse的结尾调用deferredImportSelectorHandler.process统一处理此次解析得到的所有DeferredImportSelector
- 在处理@Import过程中区分导入的类是否继承接口,继承了则将其通过this.deferredImportSelectorHandler.handle添加进入字段deferredImportSelectorHandler中,可认为其是一个List
- 注意:上面的添加是添加的实例,在实例化后会回调部分Aware接口
- DeferredImportSelectorHandler#handle接受导入这个类的配置类Class和被导入这个类,封装为DeferredImportSelectorHolder,添加进入List中
- DeferredImportSelectorHandler#process处理
- 新建一个DeferredImportSelectorGroupingHandler类,将所有DeferredImportSelectorHolder注册进入其中
- 注册大概干了什么呢?DeferredImportSelectorGroupingHandler可看做一个Map<Group, List<DeferredImportSelectorHolder>>,会调用DeferredImportSelector实例获取处理它的Group类型,并实例化,Group对象作为k,DeferredImportSelectorHolder实例作为v
- 全部注册后就是批量处理了,因为全部注入了,只需调用DeferredImportSelectorGroupingHandler#processGroupImports
- 处理又干了什么呢?遍历Group并处理能处理的DeferredImportSelector实例列表
- Group#process会处理DeferredImportSelector实例得到它要注入的类,并缓存
- 当所有能处理的处理完毕,Group#selectImports得到所有当前Group处理的要注入的类列表
- 将这个列表processImport,也就是当做被配置类@Import解析一遍
- 注意
- 被注入的数据和直接被@Import差不多,不过延迟注入了,基本上大多数和启动类相关Bean都被解析了才会注入BD,也和ImportSelector接口的差不多,不过延迟解析了
四、SpringBoot自动配置原理
自动配置 @EnableAutoConfiguration
@Import(AutoConfigurationImportSelector.class) public @interface EnableAutoConfiguration { }
@Import导入了AutoConfigurationImportSelector这个类,而这个类是一个DeferredImportSelector实现类
public class AutoConfigurationImportSelector implements DeferredImportSelector, BeanClassLoaderAware, ResourceLoaderAware, BeanFactoryAware, EnvironmentAware, Ordered {}
可以看到他实现了各种接口,在@Import处理实例化这个类时,会调用部分Aware注入一些已有的实例
public class AutoConfigurationImportSelector implements DeferredImportSelector, BeanClassLoaderAware, ResourceLoaderAware, BeanFactoryAware, EnvironmentAware, Ordered {} // 返回处理当前 DeferredImportSelector 的 Group 类型 @Override public Class<? extends Group> getImportGroup() { return AutoConfigurationGroup.class; } // AutoConfigurationImportSelector 的内部类 // 也继承了许多接口, 创建当前 Group 实例时也会回调这些 Aware 接口 private static class AutoConfigurationGroup implements DeferredImportSelector.Group, BeanClassLoaderAware, BeanFactoryAware, ResourceLoaderAware { private final Map<String, AnnotationMetadata> entries = new LinkedHashMap<>(); private final List<AutoConfigurationEntry> autoConfigurationEntries = new ArrayList<>(); private ClassLoader beanClassLoader; private BeanFactory beanFactory; private ResourceLoader resourceLoader; private AutoConfigurationMetadata autoConfigurationMetadata; // 接口回调 setter // 1. 会先调用 process // --> 会使用一个 Group 实例处理它能处理的一系列 DeferredImportSelector 实例 // --> 每一个 DeferredImportSelector 实例都可以注入数据, 现在还未注入, 仅缓存起来 @Override public void process(AnnotationMetadata annotationMetadata, DeferredImportSelector deferredImportSelector) { // 只处理 AutoConfigurationImportSelector // 说明这个 Group 仅处理这个类型的实例, 其他类型的 DeferredImportSelector 不处理 Assert.state(deferredImportSelector instanceof AutoConfigurationImportSelector, () -> String.format("Only %s implementations are supported, got %s", AutoConfigurationImportSelector.class.getSimpleName(), deferredImportSelector.getClass().getName())); // AutoConfigurationEntry 包装了要注入的自动配置类和排除了的配置类 AutoConfigurationEntry autoConfigurationEntry = ((AutoConfigurationImportSelector) deferredImportSelector) .getAutoConfigurationEntry(annotationMetadata); this.autoConfigurationEntries.add(autoConfigurationEntry); // 遍历需要注入的配置类 for (String importClassName : autoConfigurationEntry.getConfigurations()) { // 配置类全类名 -> 导入此配置类的类的注解信息 this.entries.putIfAbsent(importClassName, annotationMetadata); } // 注意上面只是将要注入的数据缓存在了当前 Group 实例中 } // 2. 调用它, 返回处理了的所有 DeferredImportSelector 实例要注入的数据 @Override public Iterable<Entry> selectImports() { if (this.autoConfigurationEntries.isEmpty()) { return Collections.emptyList(); } // 移除的配置类 Set Set<String> allExclusions = this.autoConfigurationEntries.stream() .map(AutoConfigurationEntry::getExclusions).flatMap(Collection::stream).collect(Collectors.toSet()); // 要注入的配置类 Set Set<String> processedConfigurations = this.autoConfigurationEntries.stream() .map(AutoConfigurationEntry::getConfigurations).flatMap(Collection::stream) .collect(Collectors.toCollection(LinkedHashSet::new)); // emm processedConfigurations.removeAll(allExclusions); // 排序 return sortAutoConfigurations(processedConfigurations, getAutoConfigurationMetadata()).stream() .map((importClassName) -> // 导入此配置类的类的注解信息为 + 当前被自动注入的类 new Entry(this.entries.get(importClassName), importClassName)) .collect(Collectors.toList()); } // ... } }