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());