• 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 接口的类的处理逻辑较为明显,其他的实际都不是很明显。

  • 相关阅读:
    ffmpeg使用中文使用+解释
    CentOS GCC升级到4.6.1(转)
    C#委托与直接调用方法区别
    微软面试题,倒置数组
    MSDN中介绍的图片格式
    你们的学校是几流
    VS代码模版
    正则表达式
    Visual Studio 2010中添加项目模板
    泛型详解
  • 原文地址:https://www.cnblogs.com/chenxingyang/p/16123964.html
Copyright © 2020-2023  润新知