Spring源码阅读 - @Import 处理

1. 概述

同样是 org.springframework.context.annotation.ConfigurationClassParser#doProcessConfigurationClass 开始
org.springframework.context.annotation.ConfigurationClassParser#processImports 就是处理 @Import 的,并没有将这个逻辑单独抽出来,原因应该是内部处理还依赖这个类的东西。

2. @Import

注意到这个注解不是可重复注解

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Import {

    /**
     * {@link Configuration @Configuration}, {@link ImportSelector},
     * {@link ImportBeanDefinitionRegistrar}, or regular component classes to import.
     */
    Class<?>[] value();

}

3. 解析

org.springframework.context.annotation.ConfigurationClassParser#doProcessConfigurationClass

processImports(configClass, sourceClass, getImports(sourceClass), filter, true);

获取 @Import 的类

private Set<SourceClass> getImports(SourceClass sourceClass) throws IOException {
    Set<SourceClass> imports = new LinkedHashSet<>();
    // 这里的这个 visited 后面好像是没有实际使用到的
    Set<SourceClass> visited = new LinkedHashSet<>();
    collectImports(sourceClass, imports, visited);
    return imports;
}
private void collectImports(SourceClass sourceClass, Set<SourceClass> imports, Set<SourceClass> visited)
        throws IOException {

    if (visited.add(sourceClass)) {
        // 这里不太能理解,为什么会有多个 @Import 注解 ?
        for (SourceClass annotation : sourceClass.getAnnotations()) {
            String annName = annotation.getMetadata().getClassName();
            //
            if (!annName.equals(Import.class.getName())) {
                // 这里是递归调用
                collectImports(annotation, imports, visited);
            }
        }
        imports.addAll(sourceClass.getAnnotationAttributes(Import.class.getName(), "value"));
    }
}

处理 @Import

private void processImports(ConfigurationClass configClass, SourceClass currentSourceClass,
        Collection<SourceClass> importCandidates, Predicate<String> exclusionFilter,
        boolean checkForCircularImports) {

    // 导入的类为空
    if (importCandidates.isEmpty()) {
        return;
    }

    // 循环导入的情况,暂时略具体逻辑
    if (checkForCircularImports && isChainedImportOnStack(configClass)) {
        this.problemReporter.error(new CircularImportProblem(configClass, this.importStack));
    }
    else {
        // push 了配置类
        this.importStack.push(configClass);
        try {
            for (SourceClass candidate : importCandidates) {
                // Import 的类继承了 ImportSelector 接口
                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 {
                        // 否则立即处理,将返回的字符串数组当做类全限定名数组,加载对应的 class 入内存
                        // 传入的信息是使用了 @Import 注解的类的信息
                        String[] importClassNames = selector.selectImports(currentSourceClass.getMetadata());
                        Collection<SourceClass> importSourceClasses = asSourceClasses(importClassNames, exclusionFilter);
                        // 把这些加载的类当做直接 @Import 的类进行处理,注意到原 @Import 的类并未被注入容器
                        processImports(configClass, currentSourceClass, importSourceClasses, exclusionFilter, false);
                    }
                }
                // 继承了 ImportBeanDefinitionRegistrar 接口,说明这个类有想自己向容器注入 BD 的想法,比如说 MyBatis 自己收集接口, 自己注入这些接口代理类的 BD
                else if (candidate.isAssignable(ImportBeanDefinitionRegistrar.class)) {
                    // Candidate class is an ImportBeanDefinitionRegistrar ->
                    // delegate to it to register additional bean definitions
                    Class<?> candidateClass = candidate.loadClass();
                    // 实例化
                    ImportBeanDefinitionRegistrar registrar =
                            ParserStrategyUtils.instantiateClass(candidateClass, ImportBeanDefinitionRegistrar.class,
                                    this.environment, this.resourceLoader, this.registry);
                    // 也没有立即处理, 注意这里是放到 configClass 中的
                    configClass.addImportBeanDefinitionRegistrar(registrar, currentSourceClass.getMetadata());
                }
                else {
                    // 普通类,这里的普通类包括 @Import 直接导入的没有继承上面三个接口的类,还有就是 @Import 导入了继承 ImportSelector 接口的类要注入的普通类
                    // Candidate class not an ImportSelector or ImportBeanDefinitionRegistrar ->
                    // process it as an @Configuration class
                    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 一个"普通"类和 @Import 一个继承了 ImportSelector 接口的类的处理逻辑较为明显,其他的实际都不是很明显。

posted @ 2022-04-09 22:15  YangDanMua  阅读(66)  评论(0编辑  收藏  举报