Spring源码阅读 - @Import 处理
1. 概述
同样是 org.springframework.context.annotation.ConfigurationClassParser#doProcessConfigurationClass 开始
org.springframework.context.annotation.ConfigurationClassParser#processImports 就是处理 @Import 的,并没有将这个逻辑单独抽出来,原因应该是内部处理还依赖这个类的东西。
2. @Import
注意到这个注解不是可重复注解
@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();
}
3. 解析
org.springframework.context.annotation.ConfigurationClassParser#doProcessConfigurationClass
processImports(configClass, sourceClass, getImports(sourceClass), filter, true);
获取 @Import 的类
private Set<SourceClass> getImports(SourceClass sourceClass) throws IOException {
Set<SourceClass> imports = new LinkedHashSet<>();
// 这里的这个 visited 后面好像是没有实际使用到的
Set<SourceClass> visited = new LinkedHashSet<>();
collectImports(sourceClass, imports, visited);
return imports;
}
private void collectImports(SourceClass sourceClass, Set<SourceClass> imports, Set<SourceClass> visited)
throws IOException {
if (visited.add(sourceClass)) {
// 这里不太能理解,为什么会有多个 @Import 注解 ?
for (SourceClass annotation : sourceClass.getAnnotations()) {
String annName = annotation.getMetadata().getClassName();
//
if (!annName.equals(Import.class.getName())) {
// 这里是递归调用
collectImports(annotation, imports, visited);
}
}
imports.addAll(sourceClass.getAnnotationAttributes(Import.class.getName(), "value"));
}
}
处理 @Import
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 {
// push 了配置类
this.importStack.push(configClass);
try {
for (SourceClass candidate : importCandidates) {
// Import 的类继承了 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);
}
// 继承了 DeferredImportSelector 接口(ImportSelector 的子接口)
if (selector instanceof DeferredImportSelector) {
// 稍后再处理
this.deferredImportSelectorHandler.handle(configClass, (DeferredImportSelector) selector);
}
else {
// 否则立即处理,将返回的字符串数组当做类全限定名数组,加载对应的 class 入内存
// 传入的信息是使用了 @Import 注解的类的信息
String[] importClassNames = selector.selectImports(currentSourceClass.getMetadata());
Collection<SourceClass> importSourceClasses = asSourceClasses(importClassNames, exclusionFilter);
// 把这些加载的类当做直接 @Import 的类进行处理,注意到原 @Import 的类并未被注入容器
processImports(configClass, currentSourceClass, importSourceClasses, exclusionFilter, false);
}
}
// 继承了 ImportBeanDefinitionRegistrar 接口,说明这个类有想自己向容器注入 BD 的想法,比如说 MyBatis 自己收集接口, 自己注入这些接口代理类的 BD
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 中的
configClass.addImportBeanDefinitionRegistrar(registrar, currentSourceClass.getMetadata());
}
else {
// 普通类,这里的普通类包括 @Import 直接导入的没有继承上面三个接口的类,还有就是 @Import 导入了继承 ImportSelector 接口的类要注入的普通类
// 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();
}
}
}
这里实际只有 @Import 一个"普通"类和 @Import 一个继承了 ImportSelector 接口的类的处理逻辑较为明显,其他的实际都不是很明显。