Spring创建Bean源码 - 解析配置类: 延迟导入选择器DeferredImportSelector

简介

DeferredImportSelector延迟导入选择器是Spring提供的一个扩展导入器,该导入器是ImportSelector的一个变体,该导入器是在处理配置类上@Import注解的时候注册的,当所有{@code @Configuration}配置类解析完成后才会运行所有被注册的DeferredImportSelector
该导入器的主要作用是,委托Group接口导入一组配置类。Springboot 的AutoConfigurationImportSelector实现了该接口,用于自动装配类的获取。请查看《Springboot源码-自动装配(一):AutoConfigurationImportSelector》

DeferredImportSelector接口

DeferredImportSelector继承自ImportSelector,扩展了getImportGroup方法,getImportGroup方法返回同一个Group类的DeferredImportSelector会被分到同一个组中。当所选导入是{@code @Conditional}时,这种类型的选择器可能特别有用,可能就是不同的Condition对应不同的DeferredImportSelector实现。

/**
 * {@link ImportSelector} 的变体,在解析完所有 {@code @Configuration} bean后运行。
 * 当所选导入是{@code @Conditional}时,这种类型的选择器可能特别有用。
 *
 * <p>实现还可以扩展 {@link org.springframework.core.Ordered} 接口
 * 或使用 {@link org.springframework.core.annotation.Order} 注解来指示相对于其他 {@link DeferredImportSelector DeferredImportSelectors} 的优先级。
 * 
 * <p>Springboot {@link org.springframework.boot.autoconfigure.AutoConfigurationImportSelector}实现了该接口,用于自动装配类的获取
 */
public interface DeferredImportSelector extends ImportSelector {

    /**
     * 对不同导入选择器的导入结果进行分组的接口。
     *
     * @return DeferredImportSelector所属的Group对象。
     * @since 5.0
     */
    @Nullable
    default Class<? extends Group> getImportGroup() {
        return null;
    }
}

Group接口

group接口主要用于对DeferredImportSelector进行分组,遍历Group对应的DeferredImportSelector对象集合,依次执行Group的process方法处理对应的逻辑。然后利用selectImports方法将process处理后的结果已Entry的形式返回回来。Springboot自动装配类AutoConfigurationImportSelector实现了该process接口,主要用于读取Springboot的自动装配类。以下是Springboot实现该接口的具体类和方法。请看《Springboot源码-自动装配(一):AutoConfigurationImportSelector》

/**
 * 对不同导入选择器的导入结果进行分组的接口。
 *
 * 也就是说一个Group可以对应多个DeferredImportSelector,DeferredImportSelector的getImportGroup方法返回同一个Group类,则会将这些DeferredImportSelector对象分到同一个组中。
 *
 * <p> Springboot@{@link org.springframework.boot.autoconfigure.AutoConfigurationImportSelector.AutoConfigurationGroup}实现了该接口
 * 用于获取所有的自动装配类
 *
 *
 * @since 5.0
 */
interface Group {

    /**
     * 根据标注了@Import注解的配置类的注解元数据来执行DeferredImportSelector进行配置类的导入
     *  
     * <p>
     * 1.Springboot自动装配类AutoConfigurationImportSelector实现了该process接口,主要用于读取Springboot的自动装配类。以下是Springboot实现该接口的具体类和方法
     *
     * @see org.springframework.boot.autoconfigure.AutoConfigurationImportSelector.AutoConfigurationGroup#process
     * @param metadata 标注了@Import注解的配置类的注解元数据
     */
    void process(AnnotationMetadata metadata, DeferredImportSelector selector);

    /**
     * 返回包含导入配置类的全限定名和该配置类的注解元数据的{@link Entry}集合
     */
    Iterable<Entry> selectImports();


    /**
     * 包含导入配置类的全限定名和该配置类的注解元数据的{@link Entry}
     */
    class Entry {

        //配置类的注解元数据
        private final AnnotationMetadata metadata;

        // 配置类的全限定名
        private final String importClassName;

        public Entry(AnnotationMetadata metadata, String importClassName) {
            this.metadata = metadata;
            this.importClassName = importClassName;
        }

        /**
         * Return the {@link AnnotationMetadata} of the importing
         * {@link Configuration} class.
         */
        public AnnotationMetadata getMetadata() {
            return this.metadata;
        }

        /**
         * Return the fully qualified name of the class to import.
         */
        public String getImportClassName() {
            return this.importClassName;
        }

        @Override
        public boolean equals(@Nullable Object other) {
            if (this == other) {
                return true;
            }
            if (other == null || getClass() != other.getClass()) {
                return false;
            }
            Entry entry = (Entry) other;
            return (this.metadata.equals(entry.metadata) && this.importClassName.equals(entry.importClassName));
        }

        @Override
        public int hashCode() {
            return (this.metadata.hashCode() * 31 + this.importClassName.hashCode());
        }

        @Override
        public String toString() {
            return this.importClassName;
        }
    }
}

DeferredImportSelectorHandler处理器

  1. DeferredImportSelectorHandler利用handle方法收集所有的DeferredImportSelector封装成DeferredImportSelectorHolder放入到list集合中。
  2. DeferredImportSelectorHandler利用process方法获取所有的导入类。

代码详细逻辑如下:

  1. 利用handle收集所有的DeferredImportSelector封装成DeferredImportSelectorHolder放入到list集合中。
  2. 执行类的导入
    1. 创建DeferredImportSelectorGroupingHandler对象
    2. 遍历所有的DeferredImportSelector对象,依次调用DeferredImportSelectorGroupingHandler的register方法向DeferredImportSelectorGroupingHandler中保存Group与该Group下所有DeferredImportSelector映射关系
    3. 执行DeferredImportSelectorGroupingHandler的processGroupImports方法进行类的导入
private class DeferredImportSelectorHandler {

    @Nullable
    private List<DeferredImportSelectorHolder> deferredImportSelectors = new ArrayList<>();

    /**
     * {@link DeferredImportSelector}的注册阶段
     * 处理指定的{@link DeferredImportSelector}.
     * 如果deferredImportSelector等于null,则说明{@link DeferredImportSelector}正在被收集,注册器将会将{@link DeferredImportSelector}注册到当前对象的list中
     * 如果deferredImportSelector不等于null,如果{@link DeferredImportSelector}正在被处理,则{@link DeferredImportSelector}也会根据其{@link DeferredImportSelector.Group}立即进行处理。
     *
     * @param configClass    Import注解标注的配置类
     * @param importSelector the selector to handle
     */
    public void handle(ConfigurationClass configClass, DeferredImportSelector importSelector) {
        DeferredImportSelectorHolder holder = new DeferredImportSelectorHolder(configClass, importSelector);
        if (this.deferredImportSelectors == null) {
            DeferredImportSelectorGroupingHandler handler = new DeferredImportSelectorGroupingHandler();
            handler.register(holder);
            handler.processGroupImports();
        } else {
            this.deferredImportSelectors.add(holder);
        }
    }

    /**
     * {@link DeferredImportSelector}的执行阶段阶段
     * 1.执行DeferredImportSelector的getImportSelector获取导入组Group
     * 2.实例化获取到的导入组Group
     * 3.执行导入组Group的getImports方法获取所有的导入的配置类
     * 4.调用{@link ConfigurationClassParser#processImports(ConfigurationClass, SourceClass, Collection, Predicate, boolean)}方法处理配置类
     */
    public void process() {
        List<DeferredImportSelectorHolder> deferredImports = this.deferredImportSelectors;
        this.deferredImportSelectors = null;
        try {
            if (deferredImports != null) {
                DeferredImportSelectorGroupingHandler handler = new DeferredImportSelectorGroupingHandler();
                deferredImports.sort(DEFERRED_IMPORT_COMPARATOR);
                deferredImports.forEach(handler::register);
                handler.processGroupImports();
            }
        } finally {
            this.deferredImportSelectors = new ArrayList<>();
        }
    }
}

DeferredImportSelectorGroupingHandler处理器

DeferredImportSelectorGroupingHandler处理器主要用于接受GroupDeferredImportSelector的注册,然后将每一个Group与其对应的所有DeferredImportSelector的对应关系保存起来,然后调用processGroupImports方法遍历每一个Group,执行组内的所有DeferredImportSelector,来获取所有的导入类。获取到的导入类会再次通过ConfigurationClassParser#processImports方法进行处理。

private class DeferredImportSelectorGroupingHandler {

    private final Map<Object, DeferredImportSelectorGrouping> groupings = new LinkedHashMap<>();

    private final Map<AnnotationMetadata, ConfigurationClass> configurationClasses = new HashMap<>();

    /**
     * 注册Group对象
     *
     * @param deferredImport DeferredImportSelector对象的包装器对象
     */
    public void register(DeferredImportSelectorHolder deferredImport) {
        //获取DeferredImportSelector对应的导入Group对象,Springboot的自动配置类的导入就是基于该接口进行注册的
        Class<? extends Group> group = deferredImport.getImportSelector().getImportGroup();
        //将Group对象放入当前对象的Map中,后续交由下边的processGroupImports方法进行配置类的处理
        DeferredImportSelectorGrouping grouping = this.groupings.computeIfAbsent(
                (group != null ? group : deferredImport),
                key -> new DeferredImportSelectorGrouping(createGroup(group)));
        grouping.add(deferredImport);
        this.configurationClasses.put(deferredImport.getConfigurationClass().getMetadata(),
                deferredImport.getConfigurationClass());
    }

    /**
     * 调用processImports方法处理Group对象返回的所有导入配置类
     */
    public void processGroupImports() {
        for (DeferredImportSelectorGrouping grouping : this.groupings.values()) {
            Predicate<String> exclusionFilter = grouping.getCandidateFilter();
            //获取所有的自动配置类,方式有:
            //1.又Springboot实现,功能为加载所有的自动配置类
            grouping.getImports().forEach(entry -> {
                ConfigurationClass configurationClass = this.configurationClasses.get(entry.getMetadata());
                try {
                    //处理所有的导入配置类
                    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);
                }
            });
        }
    }

    /**
     * 实例化Group对象
     *
     * @param type Group的类
     * @return 实例化Group对象
     */
    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);
    }
}

DeferredImportSelector持有器

private static class DeferredImportSelectorHolder {

    private final ConfigurationClass configurationClass;

    private final DeferredImportSelector importSelector;

    public DeferredImportSelectorHolder(ConfigurationClass configClass, DeferredImportSelector selector) {
        this.configurationClass = configClass;
        this.importSelector = selector;
    }

    public ConfigurationClass getConfigurationClass() {
        return this.configurationClass;
    }

    public DeferredImportSelector getImportSelector() {
        return this.importSelector;
    }
}

DeferredImportSelectorGrouping

遍历Group集合,然后执行每一个Group中的每一个DeferredImportSelector获取导入类。

private static class DeferredImportSelectorGrouping {

    private final DeferredImportSelector.Group group;

    private final List<DeferredImportSelectorHolder> deferredImports = new ArrayList<>();

    DeferredImportSelectorGrouping(Group group) {
        this.group = group;
    }

    public void add(DeferredImportSelectorHolder deferredImport) {
        this.deferredImports.add(deferredImport);
    }

    /**
     * <pre>
     * 1.实现1
     * @see org.springframework.boot.autoconfigure.AutoConfigurationImportSelector.AutoConfigurationGroup#process
     * 2.实现2
     * @see org.springframework.boot.autoconfigure.AutoConfigurationImportSelector.AutoConfigurationGroup#selectImports
     *
     * </pre>
     * <p>
     * <p>
     * Return the imports defined by the group.
     *
     * @return each import with its associated configuration class
     */
    public Iterable<Group.Entry> getImports() {
        for (DeferredImportSelectorHolder deferredImport : this.deferredImports) {
            /*
             * 功能实现1:加载Springboot自动配置类
             */
            this.group.process(deferredImport.getConfigurationClass().getMetadata(),
                    deferredImport.getImportSelector());
        }
        /*
         * 功能实现1:对加载进来的Springboot自动配置类进行处理,包含过滤掉排除的自动配置类、对配置类进行排序
         */
        return this.group.selectImports();
    }

    public Predicate<String> getCandidateFilter() {
        Predicate<String> mergedFilter = DEFAULT_EXCLUSION_FILTER;
        for (DeferredImportSelectorHolder deferredImport : this.deferredImports) {
            Predicate<String> selectorFilter = deferredImport.getImportSelector().getExclusionFilter();
            if (selectorFilter != null) {
                mergedFilter = mergedFilter.or(selectorFilter);
            }
        }
        return mergedFilter;
    }
}