processImports(configClass, sourceClass, getImports(sourceClass), filter, true);
先看下org.springframework.context.annotation.ConfigurationClassParser#getImports方法。
private Set<SourceClass> getImports(SourceClass sourceClass) throws IOException {
Set<SourceClass> imports = new LinkedHashSet<>();
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();
// 如果该注解不是Import,在进入到该注解中,继续找。
if (!annName.equals(Import.class.getName())) {
collectImports(annotation, imports, visited);
}
}
// 最后将import注解中的信息,封装为SourceClass,返回;如果没有Import,返回一个空集合。返回的是import注解中的类对应的sourceClass对象
imports.addAll(sourceClass.getAnnotationAttributes(Import.class.getName(), "value"));
}
}
递归遍历得到配置类中的import注解的信息。将这些信息封装为SourceClass。所以根据这个方法,可以找到嵌套在注解中的import注解。
进入org.springframework.context.annotation.ConfigurationClassParser#processImports方法。
private void processImports(ConfigurationClass configClass, SourceClass currentSourceClass,
Collection<SourceClass> importCandidates, Predicate<String> exclusionFilter,
boolean checkForCircularImports) {
// 如果没有import注解信息,直接返回,不用任何操作。
if (importCandidates.isEmpty()) {
return;
}
// 循环导入,逻辑不太清楚了,
if (checkForCircularImports && isChainedImportOnStack(configClass)) {
this.problemReporter.error(new CircularImportProblem(configClass, this.importStack));
}
else {
this.importStack.push(configClass);
try {
// 遍历所有的import注解的信息。
for (SourceClass candidate : importCandidates) {
// 如果类是ImportSelector类型的
if (candidate.isAssignable(ImportSelector.class)) {
// 得到import注解中的类的元信息
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类型的,先放在一个类似的集合中,处理完配置完配置类,统一处理。
if (selector instanceof DeferredImportSelector) {
this.deferredImportSelectorHandler.handle(configClass, (DeferredImportSelector) selector);
}
else {
// 如果不是就调用selectImports方法,发返回的是需要注入到容器的类的全限定类名
String[] importClassNames = selector.selectImports(currentSourceClass.getMetadata());
Collection<SourceClass> importSourceClasses = asSourceClasses(importClassNames, exclusionFilter);
// 继续import的逻辑,这块有一个递归调用,这里的作用是找到真正要注入的类,如果importClassNames中有一个ImportSelector类型的类,要注入的是该类中selectImport方法返回的类,而给该类,所有得有一个递归操作。
processImports(configClass, currentSourceClass, importSourceClasses, exclusionFilter, false);
}
}
else if (candidate.isAssignable(ImportBeanDefinitionRegistrar.class)) {
// 如果是ImportBeanDefinitionRegistrar类型,同样是加入到集合中,统一处理。
Class<?> candidateClass = candidate.loadClass();
ImportBeanDefinitionRegistrar registrar =
ParserStrategyUtils.instantiateClass(candidateClass, ImportBeanDefinitionRegistrar.class,
this.environment, this.resourceLoader, this.registry);
configClass.addImportBeanDefinitionRegistrar(registrar, currentSourceClass.getMetadata());
}
else {
// 如果什么也不是,就作为配置类处理,进行解析配置的逻辑。
// 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注解中类的类型,
ImportSelector:如果是子类型DeferredImportSelector放入集合中,统一处理;不是的话,调用selectImports方法,返回的类名称再次走import的逻辑,为了找到真正要注入的类(如果selectImports方法返回的类中有类型是ImportSelector,A,要注入A的selectImports放回类而非该类A)。
ImportBeanDefinitionRegistrar:放入集合中,统一处理,此时传入的注解信息是配置类的,即用@configuration注解标注的类的信息。
都不是的话;就作为配置类,走解析配置类的逻辑。
如果是ImportSelector类型的,返回的全限定类名是要注入到容器中的,作为配置类处理。
如果是ImportBeanDefinitionRegistrar,可以自己操作注册的bd。
如果是不容的类型,即就是一个简单的类名,会直接当配置类处理。
以当前解析的逻辑就是把该配置类放到配置类的缓存中。
看完源码在看下import注解的使用规则,是不是一目了然呢?