- @Import只能用在类上 ,@Import通过快速导入的方式实现把实例加入spring的IOC容器中
- 加入IOC容器的方式有很多种,@Import注解就相对很牛皮了,@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();
}
ConfigurationClassParser#doProcessConfigurationClass
中,这里是对@Import的解析
// Process any @Import annotations
processImports(configClass, sourceClass, getImports(sourceClass), filter, true);
先看一些getImports
方法,返回的是Import进来的SourceClass集合
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 {
//visited集合可以防止无限递归
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);
}
}
//将@Import进来的类加入到imports集合中
imports.addAll(sourceClass.getAnnotationAttributes(Import.class.getName(), "value"));
}
}
进入到解析@Import注解的方法中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) {
//如果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类型
if (selector instanceof DeferredImportSelector) {
//比较复杂,springboot中自动配置用到了
this.deferredImportSelectorHandler.handle(configClass, (DeferredImportSelector) selector);
}
else {
//在这里调用selectImports方法,返回所有的需要import到spring容器的beanName
String[] importClassNames = selector.selectImports(currentSourceClass.getMetadata());
Collection<SourceClass> importSourceClasses = asSourceClasses(importClassNames, exclusionFilter);
//递归处理,有可能import进来的类又有@Import注解
processImports(configClass, currentSourceClass, importSourceClasses, exclusionFilter, false);
}
}
//如果Import进来的是一个ImportBeanDefinitionRegistrar类型
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);
//加入到importBeanDefinitionRegistrars容器中,这里还没有调用registerBeanDefinitions
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());
//如果都不是,继续循环解析导入的类上面是否有@Import注解
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导入到Spring容器中的类有三种情况
如果导入的类实现了ImportSelector
,在解析的时候拿到实例,调用selectImports
方法
public interface ImportSelector {
/**
* 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.
* 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;
}
}
如果导入的类实现了ImportBeanDefinitionRegistrar
,拿到类的实例后,放到importBeanDefinitionRegistrars
容器中,实例与类的metadata之间建立映射关系。