Spring中@Import注解的使用和实现原理

Spring中@Import注解的使用和实现原理

概述

@Import 是 Spring 基于 Java 注解配置的主要组成部分,@Import 注解提供了类似 @Bean 注解的功能,介绍一下@Import注解的使用,并详细分析该注解的实现原理,同时会学习到Spring当中ImportSelector接口的和ImportBeanDefinitionRegistrar接口的使用和实现原理。

springboot 的组合注解@SpringBootApplication 其中就大量使用了@Import注解,搞懂了@Import注解,也就基本明白了@SpringBootApplication 注解在springboot中是怎样起作用的。

@Imprt注解

下图是Spring当中Import注解的源码,可以看出Import可以配合 Configuration, ImportSelector, ImportBeanDefinitionRegistrar 来使用,也可以用于一个普通类的导入。

1
2
3
4
5
6
7
8
9
10
11
12
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Import {

/**
* {@link Configuration @Configuration}, {@link ImportSelector},
* {@link ImportBeanDefinitionRegistrar}, or regular component classes to import.
*/
Class<?>[] value();

}

@Target表明了它能作用的范围,可以作用于类、接口、枚举类。

属性仅有一个value,表示的是一个类对象数组。例如value = {xx.class,yy.class},表示要将xx和yy交给Spring容器管理。

那么这些类又有什么特点呢?

大体可以分成三大类

  • 普通类
  • 实现了ImportSelector接口的类
  • 实现了ImportBeanDefinitionRegistrar接口的类

普通类注入Spring容器的方式

创建一个实体类

1
2
3
4
5
6
7
8
public class MyBean
{
public String sayHello()
{
System.out.println("MyBean Hello");
return "hello";
}
}

使用 Import 注解导入这个类

1
2
3
4
5
@Configuration
@Import(MyBean.class)
public class MyImport
{
}

使用springboot 测试

1
2
3
4
5
6
7
8
9
10
11
12
13
@SpringBootApplication
public class MyApplication
{

public static void main(String[] args)
{
ApplicationContext applicationContext = SpringApplication.run(MyApplication.class, args);

MyBean myBean = applicationContext.getBean(MyBean.class);
myBean.sayHello();
}

}

MyBean Hello 成功打印出来,说明MyBean导入了spring容器中

实现了ImportSelector接口的类注入Spring容器的方式

先来看看ImportSelector接口的定义,其中有两个方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
public interface ImportSelector {

/**
// 返回一个包含了类全限定名的数组,这些类会注入到Spring容器当中
* Select and return the names of which class(es) should be imported based on
* the {@link AnnotationMetadata} of the importing @{@link Configuration} class.
* @return the class names, or an empty array if none
*/
String[] selectImports(AnnotationMetadata importingClassMetadata);

/**
// 返回一个谓词接口,该方法制定了一个对类全限定名的排除规则来过滤一些候选的导入类,默认不排除过滤。该接口可以不实现。
* Return a predicate for excluding classes from the import candidates, to be
* transitively applied to all classes found through this selector's imports.
* <p>If this predicate returns {@code true} for a given fully-qualified
* class name, said class will not be considered as an imported configuration
* class, bypassing class file loading as well as metadata introspection.
* @return the filter predicate for fully-qualified candidate class names
* of transitively imported configuration classes, or {@code null} if none
* @since 5.2.4
*/
@Nullable
default Predicate<String> getExclusionFilter() {
return null;
}
}

定义ImportSelector实现类

1
2
3
4
5
6
7
8
public class MyImportSelector implements ImportSelector 
{
@Override
public String[] selectImports(AnnotationMetadata importingClassMetadata)
{
return new String[]{"com.dxysun.springboot.bean.MyBean"};
}
}

修改配置类

1
2
3
4
5
@Configuration
@Import(MyImportSelector.class)
public class MyImport
{
}

测试代码与之前的一样,这里不再赘述

如果实现了ImportSelector接口的getExclusionFilter()方法,MyImportSelector改为如下,表示过滤掉类全限定名为”com.dxysun.springboot.bean.MyBean”的类,该类将不会被注入到Spring容器当中,当然这里可以使用通配符的匹配方式。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
public class MyImportSelector implements ImportSelector {

@Override
public String[] selectImports(AnnotationMetadata importingClassMetadata) {
return new String[]{"hdu.gongsenlin.Normal"};
}

@Override
public Predicate<String> getExclusionFilter() {
Predicate<String> predicate = new Predicate<String>() {
@Override
public boolean test(String s) {
if (s.matches("com.dxysun.springboot.bean.MyBean")) {
return true;
}
return false;
}
};
return predicate;
}
}

实现了ImportBeanDefinitionRegistrar接口的类注入Spring容器的方式

该接口的目的是实现类的动态注入,先来看看ImportBeanDefinitionRegistrar接口的定义。

一共定义了两个同名方法,都是用于将类的BeanDefinition注入。

唯一的区别就是,2个参数的方法,只能手动的输入beanName,而3个参数的方法,可以利用BeanNameGenerator根据beanDefinition自动生成beanName

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
public interface ImportBeanDefinitionRegistrar {

/**
* Register bean definitions as necessary based on the given annotation metadata of
* the importing {@code @Configuration} class.
* <p>Note that {@link BeanDefinitionRegistryPostProcessor} types may <em>not</em> be
* registered here, due to lifecycle constraints related to {@code @Configuration}
* class processing.
* <p>The default implementation delegates to
* {@link #registerBeanDefinitions(AnnotationMetadata, BeanDefinitionRegistry)}.
* @param importingClassMetadata annotation metadata of the importing class
* @param registry current bean definition registry
* @param importBeanNameGenerator the bean name generator strategy for imported beans:
* {@link ConfigurationClassPostProcessor#IMPORT_BEAN_NAME_GENERATOR} by default, or a
* user-provided one if {@link ConfigurationClassPostProcessor#setBeanNameGenerator}
* has been set. In the latter case, the passed-in strategy will be the same used for
* component scanning in the containing application context (otherwise, the default
* component-scan naming strategy is {@link AnnotationBeanNameGenerator#INSTANCE}).
* @since 5.2
* @see ConfigurationClassPostProcessor#IMPORT_BEAN_NAME_GENERATOR
* @see ConfigurationClassPostProcessor#setBeanNameGenerator
*/
default void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry,
BeanNameGenerator importBeanNameGenerator) {

registerBeanDefinitions(importingClassMetadata, registry);
}

/**
* Register bean definitions as necessary based on the given annotation metadata of
* the importing {@code @Configuration} class.
* <p>Note that {@link BeanDefinitionRegistryPostProcessor} types may <em>not</em> be
* registered here, due to lifecycle constraints related to {@code @Configuration}
* class processing.
* <p>The default implementation is empty.
* @param importingClassMetadata annotation metadata of the importing class
* @param registry current bean definition registry
*/
default void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
}

}

编写ImportBeanDefinitionRegistrar的实现类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public class MyImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar {
@Override
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
BeanDefinitionBuilder beanDefinitionBuilder = BeanDefinitionBuilder.genericBeanDefinition(MyBean.class);
AbstractBeanDefinition beanDefinition = beanDefinitionBuilder.getBeanDefinition();
registry.registerBeanDefinition("myBean", beanDefinition);
}

//或者 使用如下的方法也可以,自动生成beanName
@Override
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry, BeanNameGenerator importBeanNameGenerator) {
BeanDefinitionBuilder beanDefinitionBuilder = BeanDefinitionBuilder.genericBeanDefinition(MyBean.class);
AbstractBeanDefinition beanDefinition = beanDefinitionBuilder.getBeanDefinition();
String beanName = importBeanNameGenerator.generateBeanName(beanDefinition, registry);
registry.registerBeanDefinition(beanName, beanDefinition);
}

}

两个方法都实现的话,只会调用有3个参数的registerBeanDefinitions方法,所以要不只实现2个参数的registerBeanDefinitions方法,要不只实现有3个参数的registerBeanDefinitions方法

修改配置类

1
2
3
4
5
6
@Configuration
@Import(MyImportBeanDefinitionRegistrar.class)
public class MyImport
{

}

测试代码与之前的一样,这里不再赘述

源码分析

接下来分析一下源码,看看Spring中是何时解析@Import注解,又是如何将3种类型的类注入到Spring容器当中的。

源码

@Import的解析 在spring IOC 中 invokeBeanFactoryPostProcessors方法下,该方法是Spring容器启动的时候,会触发的一个函数。

org.springframework.context.support.AbstractApplicationContext#invokeBeanFactoryPostProcessors

1
2
3
4
5
6
7
8
9
10
protected void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory) {
PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(beanFactory, getBeanFactoryPostProcessors());

// Detect a LoadTimeWeaver and prepare for weaving, if found in the meantime
// (e.g. through an @Bean method registered by ConfigurationClassPostProcessor)
if (beanFactory.getTempClassLoader() == null && beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) {
beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory));
beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader()));
}
}

定位到 PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(beanFactory, getBeanFactoryPostProcessors());这个方法下会调用org.springframework.context.annotation.ConfigurationClassPostProcessor#postProcessBeanDefinitionRegistry

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
@Override
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) {
int registryId = System.identityHashCode(registry);
if (this.registriesPostProcessed.contains(registryId)) {
throw new IllegalStateException(
"postProcessBeanDefinitionRegistry already called on this post-processor against " + registry);
}
if (this.factoriesPostProcessed.contains(registryId)) {
throw new IllegalStateException(
"postProcessBeanFactory already called on this post-processor against " + registry);
}
this.registriesPostProcessed.add(registryId);

processConfigBeanDefinitions(registry);
}

调用processConfigBeanDefinitions,是处理配置类,也就是加了@Configuration的类,除此之外,Appconfig也属于配置类。

processConfigBeanDefinitions代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
public void processConfigBeanDefinitions(BeanDefinitionRegistry registry) {
List<BeanDefinitionHolder> configCandidates = new ArrayList<>();
String[] candidateNames = registry.getBeanDefinitionNames();

// 遍历当前容器中已经存在的BeanDefinition,将配置类加入到configCandidates集合当中。如果该集合为空,会直接返回。
// 此处只有一个配置类appConfig,即@SpringBootApplication注解对应的启动类
for (String beanName : candidateNames) {
BeanDefinition beanDef = registry.getBeanDefinition(beanName);
if (beanDef.getAttribute(ConfigurationClassUtils.CONFIGURATION_CLASS_ATTRIBUTE) != null) {
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
if (configCandidates.isEmpty()) {
return;
}

// Sort by previously determined @Order value, if applicable
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
SingletonBeanRegistry sbr = null;
if (registry instanceof SingletonBeanRegistry) {
sbr = (SingletonBeanRegistry) registry;
if (!this.localBeanNameGeneratorSet) {
BeanNameGenerator generator = (BeanNameGenerator) sbr.getSingleton(
AnnotationConfigUtils.CONFIGURATION_BEAN_NAME_GENERATOR);
if (generator != null) {
this.componentScanBeanNameGenerator = generator;
this.importBeanNameGenerator = generator;
}
}
}

if (this.environment == null) {
this.environment = new StandardEnvironment();
}

// 初始化一个ConfigurationClassParser,调用parse方法用于解析配置类。
// Parse each @Configuration class
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 {
// 解析
parser.parse(candidates);
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());
}
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();
}
}

parse方法如下,遍历配置类候选集合,此时只有一个appConfig,它属于AnnotatedBeanDefinition类型,通过第一个if,执行parse(AnnotationMetadata metadata, String beanName)。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
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();
}

parse(AnnotationMetadata metadata, String beanName)

1
2
3
protected final void parse(AnnotationMetadata metadata, String beanName) throws IOException {
processConfigurationClass(new ConfigurationClass(metadata, beanName), DEFAULT_EXCLUSION_FILTER);
}

将元数据信息和beanName封装成ConfigurationClass对象,调用processConfigurationClass方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
protected void processConfigurationClass(ConfigurationClass configClass, Predicate<String> filter) 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, filter);
do {
// 具体的处理逻辑
sourceClass = doProcessConfigurationClass(configClass, sourceClass, filter);
}
while (sourceClass != null);

this.configurationClasses.put(configClass, configClass);
}

具体的处理逻辑由doProcessConfigurationClass实现,此时只有Spring内置的扫描器,扫描结束后,会得到扫描后的BeanDefinitionHolder集合。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
protected final SourceClass doProcessConfigurationClass(
ConfigurationClass configClass, SourceClass sourceClass, Predicate<String> filter)
throws IOException {

if (configClass.getMetadata().isAnnotated(Component.class.getName())) {
// Recursively process any member (nested) classes first
processMemberClasses(configClass, sourceClass, filter);
}

// 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();
}
// 遍历BeanDefinitionHolder集合,如果存在加了注解@Configuration的类,则会递归的调用parse
if (ConfigurationClassUtils.checkConfigurationClassCandidate(bdCand, this.metadataReaderFactory)) {
parse(bdCand.getBeanClassName(), holder.getBeanName());
}
}
}
}

// 最后到这里处理 @Import注解
// Process any @Import annotations
processImports(configClass, sourceClass, getImports(sourceClass), filter, 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;
}

最后在processImports方法中处理@Import 注解

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
private void processImports(ConfigurationClass configClass, SourceClass currentSourceClass,
Collection<SourceClass> importCandidates, Predicate<String> exclusionFilter,
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 = 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)) {
// 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 {
// 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), exclusionFilter);
}
}
}
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();
}
}
}

判断注入的候选集合是否为空,空的话直接返回

循环注入的检查

遍历注入的候选集合

3种类型执行不同的逻辑

  • 实现了ImportSelector接口的类,调用getExclusionFilter()方法,如果不为空,那么就进行过滤,过滤后调用selectImports方法(),得到要注入的类的全限定名。根据类全限定名,得到类元信息。然后递归的调用processImports方法

  • 实现了ImportBeanDefinitionRegistrar接口的类,会实例化这个类,放入集合importBeanDefinitionRegistrars当中。

  • 普通类型的类(上面两个都不满足),那么就把它当作是配置类来处理,调用processConfigurationClass方法,最终会放入到configurationClasses这个集合当中。

经过一系列的递归调用,实现了ImportBeanDefinitionRegistrar接口的类,会放入到importBeanDefinitionRegistrars集合当中,其余的类都放入到configurationClasses集合当中。

之后就会回到processConfigBeanDefinitions方法,也就是执行完了ConfigurationClassParser的parse方法

此时会执行loadBeanDefinitions将configurationClasses集合当中类加载的Spring容器当中,并且从 importBeanDefinitionRegistrars 缓存当中拿到所有的ImportBeanDefinitionRegistrar并执行registerBeanDefinitions方法。

总结

@Import注解执行的时机,解析配置类的时候,由ConfigurationClassParser当中的processImports来处理。

springboot @SpringBootApplication 在springboot中并没有直接去读这个注解,而是在processImports方法总递归读取这个注解的下的各种组合注解,最后读到@Import注解,引入springboot下ImportBeanDefinitionRegistrar接口和importBeanDefinitionRegistrars接口的实现类,实现springboot的自动装配功能。

参考

@Import详解

打赏

请我喝杯咖啡吧~

支付宝
微信