Spring 源码分析之 ImportSelector 工作原理

ImportSelector 接口是 Spring 中导入外部配置的核心接口,SpringBoot 的自动化配置和 @EnableXXX(功能性注解)核心原理都是它。

该接口只有一个方法,返回需要 Import 的类的完整类名数组。

1
2
3
4
5
6
7
8
9
package org.springframework.context.annotation;

import org.springframework.core.type.AnnotationMetadata;

public interface ImportSelector {

String[] selectImports(AnnotationMetadata importingClassMetadata);

}

根据接口注释可以看出:其主要作用是收集需要导入的配置类。

如果该接口的实现类同时实现 Aware 接口(如:EnvironmentAware,BeanFactoryAware ,BeanClassLoaderAware,ResourceLoaderAware),那么在调用其 selectImports 方法之前先调用上述接口中的方法。

如果需要在所有的 @Configuration 处理完在导入时可以实现 DeferredImportSelector 接口。

调用链

源码分析

调用 selectImports 方法的地方在 processImports,该方法处理@Import 注解的解析,如果 @Import 里导入的是 ImportSelector 接口,则会调用 selectImports 方法获取 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
private void processImports(ConfigurationClass configClass, SourceClass currentSourceClass, Collection<SourceClass> importCandidates, boolean checkForCircularImports) throws IOException {

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)) { // Import 注解中配置的是 ImportSelector 类型
Class<?> candidateClass = candidate.loadClass();
ImportSelector selector = BeanUtils.instantiateClass(candidateClass, ImportSelector.class); // 实例化
ParserStrategyUtils.invokeAwareMethods(selector, this.environment, this.resourceLoader, this.registry); // 如果该类有实现对应的 Aware 接口,则注入对应的属性
if (this.deferredImportSelectors != null && selector instanceof DeferredImportSelector) { // DeferredImportSelector 类型的放到集合中待后续处理
this.deferredImportSelectors.add(new DeferredImportSelectorHolder(configClass, (DeferredImportSelector) selector));
}
else { // 直接调用 selectImports 方法取得对应的类
String[] importClassNames = selector.selectImports(currentSourceClass.getMetadata());
Collection<SourceClass> importSourceClasses = asSourceClasses(importClassNames);
processImports(configClass, currentSourceClass, importSourceClasses, false);
}
}
else if (candidate.isAssignable(ImportBeanDefinitionRegistrar.class)) {
// 如果是 ImportBeanDefinitionRegistrar 类型
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 {
// 如果非上面两种类型,那么代表这是一个与 @Configuration 相关的类
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();
}
}
}

上述 processImports 方法在 doProcessConfigurationClass 方法中调用:

1
2
3
4
5
6
protected final SourceClass doProcessConfigurationClass(ConfigurationClass configClass, SourceClass sourceClass) throws IOException {
//....
processImports(configClass, sourceClass, getImports(sourceClass), true);
//....
return null;
}

依次往上找,发现的 ConfigurationClassParser 类入口方法是:parse,如注释中描述的,前面一大块代码都是解析 @Import,后面单独对接口DeferredImportSelector 解析:

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
public void parse(Set<BeanDefinitionHolder> configCandidates) {
this.deferredImportSelectors = new LinkedList<DeferredImportSelectorHolder>();

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

// 处理 DeferredImportSelector 接口的解析
processDeferredImportSelectors();
}

参考文章

https://blog.csdn.net/u013160932/article/details/87018724