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区分了三种类

  1. 继承了ImportSelector接口的类,直接实例化这个类,调用selectImports将返回的类全限定名数组当做配置类处理,注意这个类不被注入容器
  2. 继承了DeferredImportSelector接口(ImportSelector子接口)的类,暂时未处理,可以看到后面处理后也是讲返回的类全部调用processImports当做被直接@Import的处理
  3. 继承了ImportBeanDefinitionRegistrar接口的类,暂时未处理,【用于自定义BD注入】
  4. 普通类,当做配置类进行解析

 

 三、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);
        }
    }
    
}

 

  1. 一般来说在ConfigurationClassParser#parse的结尾调用deferredImportSelectorHandler.process统一处理此次解析得到的所有DeferredImportSelector
    1. 在处理@Import过程中区分导入的类是否继承接口,继承了则将其通过this.deferredImportSelectorHandler.handle添加进入字段deferredImportSelectorHandler中,可认为其是一个List
    2. 注意:上面的添加是添加的实例,在实例化后会回调部分Aware接口
    3. DeferredImportSelectorHandler#handle接受导入这个类的配置类Class和被导入这个类,封装为DeferredImportSelectorHolder,添加进入List中
  2. DeferredImportSelectorHandler#process处理
    1. 新建一个DeferredImportSelectorGroupingHandler类,将所有DeferredImportSelectorHolder注册进入其中
    2. 注册大概干了什么呢?DeferredImportSelectorGroupingHandler可看做一个Map<Group, List<DeferredImportSelectorHolder>>,会调用DeferredImportSelector实例获取处理它的Group类型,并实例化,Group对象作为k,DeferredImportSelectorHolder实例作为v
    3. 全部注册后就是批量处理了,因为全部注入了,只需调用DeferredImportSelectorGroupingHandler#processGroupImports
    4. 处理又干了什么呢?遍历Group并处理能处理的DeferredImportSelector实例列表
      1. Group#process会处理DeferredImportSelector实例得到它要注入的类,并缓存
      2. 当所有能处理的处理完毕,Group#selectImports得到所有当前Group处理的要注入的类列表
      3. 将这个列表processImport,也就是当做被配置类@Import解析一遍
  3. 注意
    1. 被注入的数据和直接被@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());
        }

        // ...

    }
    
}

 

posted @ 2021-10-22 20:26  YangDanMua  阅读(979)  评论(0编辑  收藏  举报