ImportSelector接口是Spring中导入外部配置的核心接口,SpringBoot的自动化配置和@EnableXXX(功能性注解)核心原理都是它。
该接口只有一个方法,返回需要Import的类的完整类名数组。
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的类。
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
方法中调用:
protected final SourceClass doProcessConfigurationClass(ConfigurationClass configClass, SourceClass sourceClass) throws IOException {
//....
processImports(configClass, sourceClass, getImports(sourceClass), true);
//....
return null;
}
依次往上找,发现的ConfigurationClassParser
类入口方法是:parse
,如注释中描述的,前面一大块代码都是解析@Import
,后面单独对接口DeferredImportSelector
解析:
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