结论
@Import 注解可以导入三种类型的类
- 导入普通类,此时直接将普通类交给
Spring管理 - 导入
ImportSelector实现类中String[] selectImports(AnnotationMetadata importingClassMetadata);方法返回的类 - 导入
ImportBeanDefinitionRegistrar实现类中registerBeanDefinitions方法注入的类
代码示例
以下代码每种方式使用的类都在同一个包下( @Configuration 默认会扫描当前包和子包 )。
Import的三种使用方式
引入普通类
java
// 普通类
public class Student {
public void sayHello() {
System.out.println("test hello");
}
}
// 配置类
@Configuration
@Import(Student.class)
public class ImportConfig {
}
// 主类
public class ImportMain {
public static void main(String[] args) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(ImportConfig.class);
Student student = context.getBean(Student.class);
student.sayHello(); // 会打印 "test hello"
}
}
结合ImportSelector
java
// 普通类
public class Student {
public void sayHello() {
System.out.println("test hello");
}
}
// 配置类
@Configuration
@Import(CusImportSelector.class) // 这里导入的是实现了 ImportSelector 接口的类
public class ImportConfig {
}
// 自定义实现 ImportSelector 接口的类
public class CusImportSelector implements ImportSelector {
@Override
public String[] selectImports(AnnotationMetadata importingClassMetadata) {
// 返回的数组就是需要导入的类全限定名
return new String[]{"org.example.imports.Student"};
}
}
// 主类
public class ImportMain {
public static void main(String[] args) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(ImportConfig.class);
Student student = context.getBean(Student.class);
student.sayHello(); // 会打印 "test hello"
}
}
结合 ImportBeanDefinitionRegistrar
java
// 普通类
public class Student {
public void sayHello() {
System.out.println("test hello");
}
}
// 配置类
@Configuration
@Import(CusImportBeanDefinitionRegistrar.class) // 这里导入的是实现了 ImportSelector 接口的类
public class ImportConfig {
}
// 自定义实现 ImportBeanDefinitionRegistrar 接口的类
public class CusImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar {
@Override
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry, BeanNameGenerator importBeanNameGenerator) {
BeanDefinitionBuilder beanDefinitionBuilder = BeanDefinitionBuilder.genericBeanDefinition(Student.class);
AbstractBeanDefinition beanDefinition = beanDefinitionBuilder.getBeanDefinition();
String beanName = importBeanNameGenerator.generateBeanName(beanDefinition, registry);
registry.registerBeanDefinition(beanName, beanDefinition);
}
}
// 主类
public class ImportMain {
public static void main(String[] args) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(ImportConfig.class);
Student student = context.getBean(Student.class);
student.sayHello(); // 会打印 "test hello"
}
}
源码流程解析
@Import 的解析实际是通过 BeanFactoryPostProcessor 实现的, 在 [[BeanFacotry的后置处理器详解]] 提到 @ComponentScan 是通过 ConfigurationClassPostProcessor 处理的,处理流程如下:
bash
AbstractApplicationContext#refresh
AbstractApplicationContext#invokeBeanFactoryPostProcessors
PostProcessorRegistrationDelegate#invokeBeanDefinitionRegistryPostProcessors
ConfigurationClassPostProcessor#postProcessBeanDefinitionRegistry
ConfigurationClassParser#parse(Set<BeanDefinitionHolder>)
ConfigurationClassParser#doProcessConfigurationClass
最终是会调用到 ConfigurationClassParser#doProcessConfigurationClass 方法,接下来就看看这个方法
java
protected final SourceClass doProcessConfigurationClass(
ConfigurationClass configClass, SourceClass sourceClass, Predicate<String> filter)
throws IOException {
// 省略
// Process any @PropertySource annotations
for (AnnotationAttributes propertySource : AnnotationConfigUtils.attributesForRepeatable(
sourceClass.getMetadata(), PropertySources.class,
org.springframework.context.annotation.PropertySource.class)) {
if (this.propertySourceRegistry != null) {
this.propertySourceRegistry.processPropertySource(propertySource);
}
else {
logger.info("Ignoring @PropertySource annotation on [" + sourceClass.getMetadata().getClassName() +
"]. Reason: Environment must implement ConfigurableEnvironment");
}
}
// 这里是处理 @ComponentScan Process any @ComponentScan annotations
Set<AnnotationAttributes> componentScans = AnnotationConfigUtils.attributesForRepeatable(
sourceClass.getMetadata(), ComponentScans.class, ComponentScan.class);
if (!componentScans.isEmpty() &&
!this.conditionEvaluator.shouldSkip(sourceClass.getMetadata(), ConfigurationPhase.REGISTER_BEAN)) {
// 省略
}
// 处理 @Import Process any @Import annotations
processImports(configClass, sourceClass, getImports(sourceClass), filter, true);
// 省略 处理 @ImportResource 等 Process any @ImportResource annotations
return null;
}
processImports 方法
java
// ConfigurationClassParser 类, 该方法只列出了重要方法
private void processImports(ConfigurationClass configClass, SourceClass currentSourceClass,
Collection<SourceClass> importCandidates, Predicate<String> exclusionFilter,
boolean checkForCircularImports) {
for (SourceClass candidate : importCandidates) {
// 导入的是 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);
}
if (selector instanceof DeferredImportSelector deferredImportSelector) {
this.deferredImportSelectorHandler.handle(configClass, deferredImportSelector);
}
else {
String[] importClassNames = selector.selectImports(currentSourceClass.getMetadata());
Collection<SourceClass> importSourceClasses = asSourceClasses(importClassNames, exclusionFilter);
processImports(configClass, currentSourceClass, importSourceClasses, exclusionFilter, false);
}
}
// 导入的是 ImportBeanDefinitionRegistrar 类型的处理流程
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.addImportBeanDefinitionRegistrar(registrar, currentSourceClass.getMetadata());
}
else {
// 既不是 ImportSelector 也不是 ImportBeanDefinitionRegistrar 类型的处理流程,当作 普通的 @Configuration 类处理
this.importStack.registerImport(
currentSourceClass.getMetadata(), candidate.getMetadata().getClassName());
processConfigurationClass(candidate.asConfigClass(configClass), exclusionFilter);
}
}
}
导入的是普通类是的处理流程
从上面源码可以看到,如果导入的是普通的类(不是 ImportSelector 也不是 ImportBeanDefinitionRegistrar 类型)则将这个普通类按照含有 @Configuration 注解的类一样进行处理, 如果是按照 @Configuration 注解的类进行处理,会将普通类变成 ConfigurationClass 类型
导入的是 ImportSelector 类型
对于导入的是 ImportSelector 类型处理代码如下
java
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);
}
if (selector instanceof DeferredImportSelector deferredImportSelector) {
this.deferredImportSelectorHandler.handle(configClass, deferredImportSelector);
}
else {
String[] importClassNames = selector.selectImports(currentSourceClass.getMetadata());
Collection<SourceClass> importSourceClasses = asSourceClasses(importClassNames, exclusionFilter);
processImports(configClass, currentSourceClass, importSourceClasses, exclusionFilter, false);
}
}
- 先调用
selectImports方法获取导入的类名数组 - 调用
asSourceClasses方法将类名数组转换为SourceClass集合 - 调用
processImports方法处理SourceClass数组, 这里就是递归调用了,递归的第一层是ImportSelector类型的类,递归的第二层就是selectImports方法中返回的普通的类了,这个就和Import导入的是普通类一样的处理流程,也就是最终是按照@Configuration注解的类处理
导入的是 ImportBeanDefinitionRegistrar 类型
对于导入的是 ImportBeanDefinitionRegistrar 类型处理代码如下
java
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 就是 ConfigurationClass
configClass.addImportBeanDefinitionRegistrar(registrar, currentSourceClass.getMetadata());
}
java
/**
* ConfigurationClass 类
*
* private final Map<ImportBeanDefinitionRegistrar, AnnotationMetadata> importBeanDefinitionRegistrars = new LinkedHashMap<>();
* /
void addImportBeanDefinitionRegistrar(ImportBeanDefinitionRegistrar registrar, AnnotationMetadata importingClassMetadata) {
this.importBeanDefinitionRegistrars.put(registrar, importingClassMetadata);
}
最终是将 ImportBeanDefinitionRegistrar 实现类放入了 ConfigurationClass 类中的 importBeanDefinitionRegistrars 属性中,那么最终是什么时候注册成 BeanDefinition 的呢?
这个就得回到 org.springframework.context.annotation.ConfigurationClassPostProcessor#processConfigBeanDefinitions 方法中了, 这里通过流程图梳理一下解析和注册两个步骤的流程
- 整体逻辑是在
ConfigurationClassPostProcessor的processConfigBeanDefinitions()方法中执行的 - 对于
@ComponentScan,@Import等解析是在ConfiguraionClassParser的doProcessConfigurationClass()方法中解析的 - 对于
ImportBeanDefinitionRegistrar类型的类在第二步解析完成之后放入了ConfigurationClass类型(就是将ImportBeanDefinitionRegistrar类型的实现类转换成ConfigurationClass类型而已)中的importBeanDefinitionRegistrars属性中 - 最后在
ConfigurationClassBeanDefinitionReader类的loadBeanDefinitionsFromRegistrars()方法中会进行BeanDefinition的注册
至此,解析和注册两个步骤的流程就解析完了