Spring源码阅读 - @Import 一个继承 DeferredImportSelector接口的类

1. DeferredImportSelector 接口

具体注释待续。
类头注释的英文翻译:ImportSelector的一个变体,在处理完所有@Configuration bean之后运行。当所选导入为@Conditional时,这种类型的选择器特别有用。
实现也可以扩展org.springframework.core.Ordered接口,或者使用org.springframework.core.annotation.Order注解来指示相对于其他DeferredImportSelectors的优先级。
实现还可以提供一个导入组,该导入组可以跨不同选择器提供额外的排序和过滤逻辑。
作用

  1. 要导入的类被延迟导入
  2. 导入组?
public interface DeferredImportSelector extends ImportSelector {

    /**
     * Return a specific import group.
     * <p>The default implementations return {@code null} for no grouping required.
     * @return the import group class, or {@code null} if none
     * @since 5.0
     */
    @Nullable
    default Class<? extends Group> getImportGroup() {
        return null;
    }


    /**
     * Interface used to group results from different import selectors.
     * @since 5.0
     */
    interface Group {

        /**
         * Process the {@link AnnotationMetadata} of the importing @{@link Configuration}
         * class using the specified {@link DeferredImportSelector}.
         */
        void process(AnnotationMetadata metadata, DeferredImportSelector selector);

        /**
         * Return the {@link Entry entries} of which class(es) should be imported
         * for this group.
         */
        Iterable<Entry> selectImports();


        /**
         * An entry that holds the {@link AnnotationMetadata} of the importing
         * {@link Configuration} class and the class name to import.
         */
        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;
            }
        }
    }

}

2. 解析逻辑

可以看到也是立即被实例化,且并未被注入容器,被放入一个 deferredImportSelectorHandler (可视为一个容器)
org.springframework.context.annotation.ConfigurationClassParser#processImports

if (candidate.isAssignable(ImportSelector.class)) {
    // Candidate class is an ImportSelector -> delegate to it to determine imports
    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 接口(ImportSelector 的子接口)
    if (selector instanceof DeferredImportSelector) {
        // 稍后再处理
        this.deferredImportSelectorHandler.handle(configClass, (DeferredImportSelector) selector);
    }
    else {
        // ...
    }
}

3. deferredImportSelectorHandler.handle & DeferredImportSelectorHandler

private class DeferredImportSelectorHandler {

    /**
     * 类似 BeanDefinitionHolder, 对 DeferredImportSelector 和 ConfigurationClass 封装一下
     */
    @Nullable
    private List<DeferredImportSelectorHolder> deferredImportSelectors = new ArrayList<>();

    public void handle(ConfigurationClass configClass, DeferredImportSelector importSelector) {
        DeferredImportSelectorHolder holder = new DeferredImportSelectorHolder(configClass, importSelector);
        // emm, 这是考虑到并发处理吗, 感觉好像也不对, 如果在 process 中, 则立即处理
        if (this.deferredImportSelectors == null) {
            // 实际上这里的逻辑和 process 是一致的
            DeferredImportSelectorGroupingHandler handler = new DeferredImportSelectorGroupingHandler();
            handler.register(holder);
            handler.processGroupImports();
        }
        else {
            // 否则添加等待批量处理
            this.deferredImportSelectors.add(holder);
        }
    }

    public void process() {
        List<DeferredImportSelectorHolder> deferredImports = this.deferredImportSelectors;
        this.deferredImportSelectors = null;
        try {
            if (deferredImports != null) {
                // 这个应该是处理器
                DeferredImportSelectorGroupingHandler handler = new DeferredImportSelectorGroupingHandler();
                deferredImports.sort(DEFERRED_IMPORT_COMPARATOR);
                // 每一个进行 register
                deferredImports.forEach(handler::register);
                // 然后批量处理
                handler.processGroupImports();
            }
        }
        finally {
            this.deferredImportSelectors = new ArrayList<>();
        }
    }
}

4. 实际处理流程 DeferredImportSelectorGroupingHandler

由上面可看出先对每个 selector 执行 DeferredImportSelectorGroupingHandler#register,然后批量处理 DeferredImportSelectorGroupingHandler#processGroupImports
暂略,因为还不知道 group 的作用

5. 实际调用时机

由上面可看出 handle 会将 DeferredImportSelector 暂时存储,还未执行。
ConfigurationClassParser 处理配置类就是这个,而这个方法只会被 org.springframework.context.annotation.ConfigurationClassPostProcessor 调用,如果我们传入一个启动类,那么当这个启动类被处理完毕,才会执行 process。

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 (BeanDefinitionStoreException ex) {
            throw ex;
        }
        catch (Throwable ex) {
            throw new BeanDefinitionStoreException(
                    "Failed to parse configuration class [" + bd.getBeanClassName() + "]", ex);
        }
    }

    this.deferredImportSelectorHandler.process();
}
posted @ 2022-04-09 23:10  YangDanMua  阅读(148)  评论(0编辑  收藏  举报