文章目录
- 一、简介
- 二、@Import注解的几种用法
- 三、@Import注解源码解析
- 1、ConfigurationClassPostProcessor
- 2、ConfigurationClassPostProcessor 类的 postProcessBeanDefinitionRegistry 方法
- 3、ConfigurationClassParser 类的 parse 方法
- 4、处理 ImportBeanDefinitionRegistrar 接口实现类
- 5、处理 ImportSelector 接口实现类
- 6、处理 DeferredImportSelector 接口实现类
一、简介
本文将对 Spring 如何处理 @Import 注解的源码进行解析
二、@Import注解的几种用法
在@Import注解的参数里可以填写一个类的数组,而源码上已经告诉我们常用的几种导入类型

- 导入的类是一个标注了
@Configuration的配置类:Spring容器实例化这个配置类 - 导入的类是
ImportSelector接口的实现类:如果导入的类是ImportSelector接口的实现类,实例化这个类之后,会执行其selectImports方法,如果实现的是ImportSelector接口的子类DeferredImportSelector,会执行其selectImports方法,但是时机会延后,这个后面具体讲 - 导入的类是
ImportBeanDefinitionRegistrar接口的实现类:如果导入的类是ImportBeanDefinitionRegistrar接口的实现类,实例化这个类之后,会执行其registerBeanDefinitions方法
三、@Import注解源码解析
1、ConfigurationClassPostProcessor
下面通过源码来看 Spring 是怎么处理 @Import 注解的,关于@Import注解的处理过程,在 ConfigurationClassPostProcessor 这个类里,这个类是用来处理 @Configuration 注解相关逻辑的,它实现了 BeanDefinitionRegistryPostProcessor 接口,而 BeanDefinitionRegistryPostProcessor 接口又是 BeanFactoryPostProcessor 的子接口,熟悉 Spring 源码的同学会比较熟悉这两个类,这是Spring的后置处理器
BeanFactoryPostProcessor:用于修改Bean定义(BeanDefinition)BeanDefinitionRegistryPostProcessor:用来注册BeanDefinition到Spring容器里
具体这里就不展开了,想了解的可以去看看 Spring 的核心方法 refresh 方法里的 invokeBeanFactoryPostProcessors(beanFactory);,这里只需要知道,在 Spring 容器启动过程中,会调用 ConfigurationClassPostProcessor 类的 postProcessBeanDefinitionRegistry 方法,下面我们从这个方法的入口开始看
2、ConfigurationClassPostProcessor 类的 postProcessBeanDefinitionRegistry 方法

前面那一段,是一个防重复处理的逻辑,不用关心,重点是 processConfigBeanDefinitions 方法,跟进去看下
//ConfigurationClassPostProcessor
public void processConfigBeanDefinitions(BeanDefinitionRegistry registry) {
//1、找到所有的配置类
List<BeanDefinitionHolder> configCandidates = new ArrayList<>();
String[] candidateNames = registry.getBeanDefinitionNames();
for (String beanName : candidateNames) {
BeanDefinition beanDef = registry.getBeanDefinition(beanName);
if (ConfigurationClassUtils.isFullConfigurationClass(beanDef) ||
ConfigurationClassUtils.isLiteConfigurationClass(beanDef)) {
if (logger.isDebugEnabled()) {
logger.debug("Bean definition has already been processed as a configuration class: " + beanDef);
}
}
else if (ConfigurationClassUtils.checkConfigurationClassCandidate(beanDef, this.metadataReaderFactory)) {
configCandidates.add(new BeanDefinitionHolder(beanDef, beanName));
}
}
// Return immediately if no @Configuration classes were found
//2、如果没找到配置类就直接返回
if (configCandidates.isEmpty()) {
return;
}
// Sort by previously determined @Order value, if applicable
//3、为找到的配置类排序
configCandidates.sort((bd1, bd2) -> {
int i1 = ConfigurationClassUtils.getOrder(bd1.getBeanDefinition());
int i2 = ConfigurationClassUtils.getOrder(bd2.getBeanDefinition());
return Integer.compare(i1, i2);
});
// Detect any custom bean name generation strategy supplied through the enclosing application context
//4、如果registry是SingletonBeanRegistry类型,且包含这个CONFIGURATION_BEAN_NAME_GENERATOR实例,就设置两个属性
SingletonBeanRegistry sbr = null;
if (registry instanceof SingletonBeanRegistry) {
sbr = (SingletonBeanRegistry) registry;
if (!this.localBeanNameGeneratorSet) {
BeanNameGenerator generator = (BeanNameGenerator) sbr.getSingleton(CONFIGURATION_BEAN_NAME_GENERATOR);
if (generator != null) {
this.componentScanBeanNameGenerator = generator;
this.importBeanNameGenerator = generator;
}
}
}
if (this.environment == null) {
this.environment = new StandardEnvironment();
}
// Parse each @Configuration class
//5、实例化ConfigurationClassParser对象
ConfigurationClassParser parser = new ConfigurationClassParser(
this.metadataReaderFactory, this.problemReporter, this.environment,
this.resourceLoader, this.componentScanBeanNameGenerator, registry);
Set<BeanDefinitionHolder> candidates = new LinkedHashSet<>(configCandidates);
Set<ConfigurationClass> alreadyParsed = new HashSet<>(configCandidates.size());
do {
//6、处理配置类
parser.parse(candidates);
//7、验证配置类的合法性和正确性
parser.validate();
Set<ConfigurationClass> configClasses = new LinkedHashSet<>(parser.getConfigurationClasses());
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());
}
//加载Bean定义到Spring容器里
this.reader.loadBeanDefinitions(configClasses);
alreadyParsed.addAll(configClasses);
candidates.clear();
if (registry.getBeanDefinitionCount() > candidateNames.length) {
String[] newCandidateNames = registry.getBeanDefinitionNames();
Set<String> oldCandidateNames = new HashSet<>(Arrays.asList(candidateNames));
Set<String> alreadyParsedClasses = new HashSet<>();
for (ConfigurationClass configurationClass : alreadyParsed) {
alreadyParsedClasses.add(configurationClass.getMetadata().getClassName());
}
for (String candidateName : newCandidateNames) {
if (!oldCandidateNames.contains(candidateName)) {
BeanDefinition bd = registry.getBeanDefinition(candidateName);
if (ConfigurationClassUtils.checkConfigurationClassCandidate(bd, this.metadataReaderFactory) &&
!alreadyParsedClasses.contains(bd.getBeanClassName())) {
candidates.add(new BeanDefinitionHolder(bd, candidateName));
}
}
}
candidateNames = newCandidateNames;
}
}
while (!candidates.isEmpty());
// Register the ImportRegistry as a bean in order to support ImportAware @Configuration classes
if (sbr != null && !sbr.containsSingleton(IMPORT_REGISTRY_BEAN_NAME)) {
sbr.registerSingleton(IMPORT_REGISTRY_BEAN_NAME, parser.getImportRegistry());
}
if (this.metadataReaderFactory instanceof CachingMetadataReaderFactory) {
// Clear cache in externally provided MetadataReaderFactory; this is a no-op
// for a shared cache since it'll be cleared by the ApplicationContext.
((CachingMetadataReaderFactory) this.metadataReaderFactory).clearCache();
}
}
这个方法可以简单的概括成以下几个步骤:
- 找到所有的配置类;
- 循环解析每个配置类;
- 把配置类加载到 Spring 容器里;
最重要的就是解析配置类,ConfigurationClassParser 类的 parse 方法,我们跟进去看下
3、ConfigurationClassParser 类的 parse 方法
//ConfigurationClassParser
public void parse(Set<BeanDefinitionHolder> configCandidates) {
for (BeanDefinitionHolder holder : configCandidates) {
BeanDefinition bd = holder.getBeanDefinition();
try {
if (bd instanceof AnnotatedBeanDefinition) {
parse(((AnnotatedBeanDefinition) bd).getMetadata(), holder.getBeanName());
}
else if (bd instanceof AbstractBeanDefinition && ((AbstractBeanDefinition) bd).hasBeanClass()) {
parse(((AbstractBeanDefinition) bd).getBeanClass(), holder.getBeanName());
}
else {
parse(bd.getBeanClassName(), holder.getBeanName());
}
}
catch (BeanDefinitionStoreException ex) {
throw ex;
}
catch (Throwable ex) {
throw new BeanDefinitionStoreException(
"Failed to parse configuration class [" + bd.getBeanClassName() + "]", ex);
}
}
this.deferredImportSelectorHandler.process();
}
不论是哪个 if 条件,最终都会走到 ConfigurationClassParser 类的 processConfigurationClass 方法里,而且这些方法会将 DeferredImportSelector 接口的实现类放到 deferredImportSelectorHandler 里,在这个方法最后,调用这些类

这里先跳过,我们先看 ConfigurationClassParser 类的 processConfigurationClass 方法
//ConfigurationClassParser
protected void processConfigurationClass(ConfigurationClass configClass) throws IOException {
if (this.conditionEvaluator.shouldSkip(configClass.getMetadata(), ConfigurationPhase.PARSE_CONFIGURATION)) {
return;
}
ConfigurationClass existingClass = this.configurationClasses.get(configClass);
if (existingClass != null) {
if (configClass.isImported()) {
if (existingClass.isImported()) {
existingClass.mergeImportedBy(configClass);
}
// Otherwise ignore new imported config class; existing non-imported class overrides it.
return;
}
else {
// Explicit bean definition found, probably replacing an import.
// Let's remove the old one and go with the new one.
this.configurationClasses.remove(configClass);
this.knownSuperclasses.values().removeIf(configClass::equals);
}
}
// Recursively process the configuration class and its superclass hierarchy.
SourceClass sourceClass = asSourceClass(configClass);
do {
sourceClass = doProcessConfigurationClass(configClass, sourceClass);
}
while (sourceClass != null);
this.configurationClasses.put(configClass, configClass);
}
重点是 doProcessConfigurationClass 方法,跟进
//ConfigurationClassParser
@Nullable
protected final SourceClass doProcessConfigurationClass(ConfigurationClass configClass, SourceClass sourceClass)
throws IOException {
if (configClass.getMetadata().isAnnotated(Component.class.getName())) {
// Recursively process any member (nested) classes first
processMemberClasses(configClass, sourceClass);
}
// Process any @PropertySource annotations
for (AnnotationAttributes propertySource : AnnotationConfigUtils.attributesForRepeatable(
sourceClass.getMetadata(), PropertySources.class,
org.springframework.context.annotation.PropertySource.class)) {
if (this.environment instanceof ConfigurableEnvironment) {
processPropertySource(propertySource);
}
else {
logger.info("Ignoring @PropertySource annotation on [" + sourceClass.getMetadata().getClassName() +
"]. Reason: Environment must implement ConfigurableEnvironment");
}
}
// 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)) {
for (AnnotationAttributes componentScan : componentScans) {
// The config class is annotated with @ComponentScan -> perform the scan immediately
Set<BeanDefinitionHolder> scannedBeanDefinitions =
this.componentScanParser.parse(componentScan, sourceClass.getMetadata().getClassName());
// Check the set of scanned definitions for any further config classes and parse recursively if needed
for (BeanDefinitionHolder holder : scannedBeanDefinitions) {
BeanDefinition bdCand = holder.getBeanDefinition().getOriginatingBeanDefinition();
if (bdCand == null) {
bdCand = holder.getBeanDefinition();
}
if (ConfigurationClassUtils.checkConfigurationClassCandidate(bdCand, this.metadataReaderFactory)) {
parse(bdCand.getBeanClassName(), holder.getBeanName());
}
}
}
}
// Process any @Import annotations
processImports(configClass, sourceClass, getImports(sourceClass), true);
// Process any @ImportResource annotations
AnnotationAttributes importResource =
AnnotationConfigUtils.attributesFor(sourceClass.getMetadata(), ImportResource.class);
if (importResource != null) {
String[] resources = importResource.getStringArray("locations");
Class<? extends BeanDefinitionReader> readerClass = importResource.getClass("reader");
for (String resource : resources) {
String resolvedResource = this.environment.resolveRequiredPlaceholders(resource);
configClass.addImportedResource(resolvedResource, readerClass);
}
}
// Process individual @Bean methods
Set<MethodMetadata> beanMethods = retrieveBeanMethodMetadata(sourceClass);
for (MethodMetadata methodMetadata : beanMethods) {
configClass.addBeanMethod(new BeanMethod(methodMetadata, configClass));
}
// Process default methods on interfaces
processInterfaces(configClass, sourceClass);
// Process superclass, if any
if (sourceClass.getMetadata().hasSuperClass()) {
String superclass = sourceClass.getMetadata().getSuperClassName();
if (superclass != null && !superclass.startsWith("java") &&
!this.knownSuperclasses.containsKey(superclass)) {
this.knownSuperclasses.put(superclass, configClass);
// Superclass found, return its annotation metadata and recurse
return sourceClass.getSuperClass();
}
}
// No superclass -> processing is complete
return null;
}
这个方法也是很长的一段,关于 @Import 注解的其实就在 processImports 方法里,我们跟进看下
//ConfigurationClassParser
private void processImports(ConfigurationClass configClass, SourceClass currentSourceClass,
Collection<SourceClass> importCandidates, boolean checkForCircularImports) {
if (importCandidates.isEmpty()) {
return;
}
if (checkForCircularImports && isChainedImportOnStack(configClass)) {
this.problemReporter.error(new CircularImportProblem(configClass, this.importStack));
}
else {
this.importStack.push(configClass);
try {
for (SourceClass candidate : importCandidates) {
if (candidate.isAssignable(ImportSelector.class)) {
// Candidate class is an ImportSelector -> delegate to it to determine imports
Class<?> candidateClass = candidate.loadClass();
ImportSelector selector = BeanUtils.instantiateClass(candidateClass, ImportSelector.class);
ParserStrategyUtils.invokeAwareMethods(
selector, this.environment, this.resourceLoader, this.registry);
if (selector instanceof DeferredImportSelector) {
this.deferredImportSelectorHandler.handle(
configClass, (DeferredImportSelector) selector);
}
else {
String[] importClassNames = selector.selectImports(currentSourceClass.getMetadata());
Collection<SourceClass> importSourceClasses = asSourceClasses(importClassNames);
processImports(configClass, currentSourceClass, importSourceClasses, false);
}
}
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 =
BeanUtils.instantiateClass(candidateClass, ImportBeanDefinitionRegistrar.class);
ParserStrategyUtils.invokeAwareMethods(
registrar, this.environment, this.resourceLoader, this.registry);
configClass.addImportBeanDefinitionRegistrar(registrar, currentSourceClass.getMetadata());
}
else {
// Candidate class not an ImportSelector or ImportBeanDefinitionRegistrar ->
// process it as an @Configuration class
this.importStack.registerImport(
currentSourceClass.getMetadata(), candidate.getMetadata().getClassName());
processConfigurationClass(candidate.asConfigClass(configClass));
}
}
}
catch (BeanDefinitionStoreException ex) {
throw ex;
}
catch (Throwable ex) {
throw new BeanDefinitionStoreException(
"Failed to process import candidates for configuration class [" +
configClass.getMetadata().getClassName() + "]", ex);
}
finally {
this.importStack.pop();
}
}
}
可以看到核心代码就是对 @Import 注解的参数,那个 Class 数组做循环处理,而 if 条件是按我们之前所说的三种情况做区分的

@Configuration 注解类型的就不讲了,就是再回去调用处理 @Configuration 注解的方法,下面重点看下 ImportBeanDefinitionRegistrar 接口和 ImportSelector 接口的场景
4、处理 ImportBeanDefinitionRegistrar 接口实现类

先是实例化这个类,如果这个类实现了 Aware 相关的接口,就去设置下相关的属性,最后调用 addImportBeanDefinitionRegistrar 方法,将对象放到 importBeanDefinitionRegistrars 这个 map 里

那么这个类的 registerBeanDefinitions 方法究竟在什么时候调用的呢?
上面我们讲到在解析完配置类之后,会调用 this.reader.loadBeanDefinitions(configClasses); 方法,我们跟进这个方法

继续跟进 loadBeanDefinitionsForConfigurationClass 方法

configClass.getImportBeanDefinitionRegistrars() 方法就是获取的上面所说的 importBeanDefinitionRegistrars 这个map,继续跟进 loadBeanDefinitionsFromRegistrars 方法

可以看到循环map,调用了 registerBeanDefinitions 方法
5、处理 ImportSelector 接口实现类

同样的,先实例化对象,然后处理 Aware 相关属性注入,然后开始区分了,如果是 DeferredImportSelector 接口的实现类,就封装成 DeferredImportSelectorHolder 对象,添加到 deferredImportSelectors 这个集合里,这个前面有说过,为了延迟调用,如果不是 DeferredImportSelector 接口的实现类,那就是 ImportSelector 接口的实现类,那么就先调用其 selectImports 方法,这个方法会返回 bean 的名字,然后转成 SourceClass 对象,再调用 processImports 方法处理,然后就看 selectImports 方法返回的 bean 是什么类型,再判断处理
总结一下,就是
- 如果实现了
DeferredImportSelector接口,那么就存到deferredImportSelectors集合里,等待后续处理 - 如果没有实现
DeferredImportSelector接口,那么是实现了ImportSelector接口,直接调用其selectImports方法
所以,实现了 DeferredImportSelector 接口的类的 selectImports 方法,在什么时候调用的呢?
6、处理 DeferredImportSelector 接口实现类
我们回到 ConfigurationClassParser 类的 parse 方法

可以看到最后一步,就是处理所有 DeferredImportSelector 接口的实现类(后面简称deferredImports)的方法,我们跟进去

这个方法里,先把所有的 deferredImports 排序,然后调用 DeferredImportSelectorGroupingHandler 的 register 方法,把这些类进行分组,最后再调用 processGroupImports 方法处理,跟进这个方法

可以看到对分组后的map,获取其内容,然后进行循环,获取每个分组中的 deferredImports 循环,调用 processImports 方法,我们看下 grouping.getImports() 返回的是什么

可以看到,正是调用 selectImports 方法的返回,所以处理 DeferredImportSelector 接口的实现类,和处理 ImportSelector 接口的实现类,大致是差不多的,只不过 DeferredImportSelector 要延迟到最后处理,而且会根据不同的顺序和分组,分批处理。
dler的register方法,把这些类进行分组,最后再调用processGroupImports` 方法处理,跟进这个方法

可以看到对分组后的map,获取其内容,然后进行循环,获取每个分组中的 deferredImports 循环,调用 processImports 方法,我们看下 grouping.getImports() 返回的是什么

可以看到,正是调用 selectImports 方法的返回,所以处理 DeferredImportSelector 接口的实现类,和处理 ImportSelector 接口的实现类,大致是差不多的,只不过 DeferredImportSelector 要延迟到最后处理,而且会根据不同的顺序和分组,分批处理。


















