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());
posted @ 2022-04-10 16:48  YangDanMua  阅读(76)  评论(0编辑  收藏  举报