文档翻译
指示要导入的一个或多个组件类——通常是@Configuration类。 提供与 Spring XML 中<import/>元素等效的功能。允许导入@Configuration类、 ImportSelector和ImportBeanDefinitionRegistrar实现,以及常规组件类(从 4.2 开始;类似于AnnotationConfigApplicationContext.register )
何时解析@Import
答:处理配置类时。具体代码分析如下: ConfigurationClassParser#processConfigurationClass会调用 ConfigurationClassParser#doProcessConfigurationClass方法, 在doProcessConfigurationClass中如下代码处理:(这一块属于ConfigurationClassPostProcessor相关的,这里不做介绍,简单可理解为扫描出的bean都会经过此处代码处理)
processImports(configClass, sourceClass, getImports(sourceClass), filter, true);
getImports就是递归查找sourceClass上的@Import注解的值,就不展开看了,只看处理方法processImports。
processImports 处理@Import
for (SourceClass candidate : importCandidates) {
if (candidate.isAssignable(ImportSelector.class)) {
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);
}
if (selector instanceof DeferredImportSelector) {
this.deferredImportSelectorHandler.handle(configClass, (DeferredImportSelector) selector);
}
else {
String[] importClassNames = selector.selectImports(currentSourceClass.getMetadata());
Collection<SourceClass> importSourceClasses = asSourceClasses(importClassNames, exclusionFilter);
processImports(configClass, currentSourceClass, importSourceClasses, exclusionFilter, false);
}
}
else if (candidate.isAssignable(ImportBeanDefinitionRegistrar.class)) {
Class<?> candidateClass = candidate.loadClass();
ImportBeanDefinitionRegistrar registrar =
ParserStrategyUtils.instantiateClass(candidateClass, ImportBeanDefinitionRegistrar.class,
this.environment, this.resourceLoader, this.registry);
configClass.addImportBeanDefinitionRegistrar(registrar, currentSourceClass.getMetadata());
}
else {
this.importStack.registerImport(
currentSourceClass.getMetadata(), candidate.getMetadata().getClassName());
processConfigurationClass(candidate.asConfigClass(configClass), exclusionFilter);
}
}
- 候选类是一个ImportSelector,委托给ImportSelector以确定导入(导入其它bean)
- 候选类是一个ImportBeanDefinitionRegistrar,委托给ImportBeanDefinitionRegistrar注册其他bean定义
- 候选类不是ImportSelector或ImportBeanDefinitionRegistrar,将其作为@Configuration类处理。
ImportSelector处理
这里分为两种情况做了处理。
- DeferredImportSelector(延期的的ImportSelector):ImportSelector的一种变体,在处理完所有@Configuration bean 后运行。当所选导入是@Conditional时,这种类型的选择器可能特别有用。
@Import(AutoConfigurationImportSelector.class)
public @interface EnableAutoConfiguration {
EnableAutoConfiguration上的 AutoConfigurationImportSelector就是这种类型。都说了在处理完所有@Configuration bean后才出处理DeferredImportSelector,所以这里的处理目前也很简单,就是包装了下放到了一个list集合中,真正的处理后续文章会说明(springboot starter)。(简化后代码)
public void handle(ConfigurationClass configClass, DeferredImportSelector importSelector) {
DeferredImportSelectorHolder holder = new DeferredImportSelectorHolder(configClass, importSelector);
this.deferredImportSelectors.add(holder);
}
- 非DeferredImportSelector类型处理方式:调用importSelector接口方法selectImports()结果作为importSourceClasses ,然后又重新调用processImports 方法递归处理。这里有一点可以注意下,就是实例化ImportSelector代码,selectImports()实现里可以添加扩展。
ImportBeanDefinitionRegistrar处理
存入ConfigurationClass属性Map<ImportBeanDefinitionRegistrar, AnnotationMetadata> importBeanDefinitionRegistrars中,后续会做真正的处理。处理就在ConfigurationClassPostProcessor#processConfigBeanDefinitions方法中。
this.reader.loadBeanDefinitions(configClasses);
@Configuration类型处理
Configuration处理会调用ConfigurationClassParser#processConfigurationClass,文章开头红色标识的。是的又开始了新一轮的循环。这里只是作为@Configuration类型处理,并不是说这个类上非得加上@Configuration注解,普通的bean也是可以的。只不过后续的解析过程中没有解析到@Import、@Bean等 而已。
|