zoukankan      html  css  js  c++  java
  • 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());
            }
    
            // ...
    
        }
        
    }
  • 相关阅读:
    深入理解JavaScript中的this关键字
    使用yii的layout,加入<?php echo $content; ?>这句话时,它会自动在子页面上面添加一个div包裹
    使用 BEGINCONTENT() 和 ENDCONTENT() 设定 YII 的 LAYOUTS
    孙悟空的师傅是谁
    PHP MemCached高级缓存配置图文教程
    C++中的基类与派生类
    矩阵快速幂
    华为上机测试题
    2016网易研发题目
    冒泡排序
  • 原文地址:https://www.cnblogs.com/chenxingyang/p/15440519.html
Copyright © 2011-2022 走看看