• Spring源码阅读 @Import一个继承 ImportBeanDefinitionRegistrar 的类


    1. ImportBeanDefinitionRegistrar

    
    // 和 DeferredImportSelectors 类似, 也可以自己注册 BeanDefinition
    // 不过这个接口可以继承 EnvironmentAware、BeanFactoryAware、BeanClassLoaderAware、ResourceLoaderAware, 或者提供参数为 Environment、... 的构造函数\
    // 不过也只是经过了特殊的的初始化, 和普通 Bean 通过 getBean 经过完整生命周期还是不一样的
    public interface ImportBeanDefinitionRegistrar {
    
        // 注册BD, 默认行为啥也不做
        // 不建议在这里注入 BeanDefinitionRegistryPostProcessor, 因为处理到他的时候, 配置类的处理流程已经完毕【??待续后续代码】
        default void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry,
                BeanNameGenerator importBeanNameGenerator) {
    
            registerBeanDefinitions(importingClassMetadata, registry);
        }
    
        default void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
        }
    
    }
    

    2. 处理流程

    org.springframework.context.annotation.ConfigurationClassParser#processImports

    // Import 的类继承了 ImportSelector 接口
    if (candidate.isAssignable(ImportSelector.class)) {
        // ...
        ImportSelector selector = ParserStrategyUtils.instantiateClass(candidateClass, ImportSelector.class,
                                    this.environment, this.resourceLoader, this.registry);
        // ...
    }
    // 继承了 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();
        // 实例化, 这个调用和上面的调用是一致的, 也就是说 ImportSelector 也可以继承一些 Aware 接口, 或提供构造函数
        ImportBeanDefinitionRegistrar registrar =
                ParserStrategyUtils.instantiateClass(candidateClass, ImportBeanDefinitionRegistrar.class,
                        this.environment, this.resourceLoader, this.registry);
        // 也没有立即处理, 注意这里是放到 configClass 中的
        // 而 DeferredImportSelector 是放到了一个集合中
        configClass.addImportBeanDefinitionRegistrar(registrar, currentSourceClass.getMetadata());
    }
    

    3. 处理时机

    注意上面是将这个 ImportBeanDefinitionRegistrar 绑定在了 configClass 中,从这就可看出它的执行应该是较晚的,实际比 DeferredImportSelector 还晚。
    回到 ConfigurationClassPostProcessor#processConfigBeanDefinitions

    do {
        // 这里是解析配置类, DeferredImportSelector  就是在里面就被调用了
        parser.parse(candidates);
        parser.validate();
    
        // 这里面应该是 Parser 记录的解析过的配置类
        Set<ConfigurationClass> configClasses = new LinkedHashSet<>(parser.getConfigurationClasses());
        // 去除已经解析过的,这个实际主要是用在后面 loadBeanDefinitions 去除不必要的 BD, removeAll 是为了减少判断
        //  alreadyParsed 是上一次循环已经解析过的,去除上一次解析过的就是这一次解析过的,主要是 Parser 是复用的,所以需要 removeAll
        configClasses.removeAll(alreadyParsed);
    
        // Read the model and create bean definitions based on its content
        if (this.reader == null) {
            this.reader = new ConfigurationClassBeanDefinitionReader(
                    registry, this.sourceExtractor, this.resourceLoader, this.environment,
                    this.importBeanNameGenerator, parser.getImportRegistry());
        }
        // 这里就处理了 ImportBeanDefinitionRegistrar, 迟于 DeferredImportSelector
        this.reader.loadBeanDefinitions(configClasses);
        alreadyParsed.addAll(configClasses);
        // ...
    }
    while (!candidates.isEmpty());
    
  • 相关阅读:
    【集合遍历-Java】
    【eclipse】使用说明
    【Java IO流】浅谈io,bio,nio,aio
    【Mysql数据库】知识点总结
    【struts2】学习笔记
    【EL&JSTL】学习笔记
    思科交换机-常用命令及配置
    【JDBC-MVC模式】开发实例
    【JDBC】java连接MySQL数据库步骤
    【JDBC】Servlet实例
  • 原文地址:https://www.cnblogs.com/chenxingyang/p/16126521.html
Copyright © 2020-2023  润新知