前言

分析SpringBoot启动流程时遇到的@Import 注解,不明所以然,所以先翻一下注解的源码。

源码

1
2
3
4
5
6
7
8
9
10
11
@Target(ElementType.TYPE) // 类上使用
@Retention(RetentionPolicy.RUNTIME) // 生命周期
@Documented // 文档
public @interface Import {
/**
* {@link Configuration @Configuration}, {@link ImportSelector},
* {@link ImportBeanDefinitionRegistrar}, or regular component classes to import.
* 可以配合 Configuration、ImportSelector、ImportBeanDefinitionRegistrar使用
*/
Class<?>[] value();
}

使用方式

简单使用方法

这种方式可以直接把类加入到Spring IOC容器

1
2
3
@Configuration
@Import(value={UserServiceImpl.class})
public class Config {}

这种方式很少用,原因有二:

  1. 直接使用@Bean注解代替更加方便
  2. 仅能调用无参构造

结合ImportBeanDefinitionRegistrar接口

源码

1
2
3
4
5
6
7
8
9
10
11
public interface ImportBeanDefinitionRegistrar {
default void registerBeanDefinitions(
AnnotationMetadata importingClassMetadata, // 通过这个参数可以拿到类的元数据信息
BeanDefinitionRegistry registry, // 通过这个参数可以操作IOC容器
BeanNameGenerator importBeanNameGenerator) // BeanNameGenerator 注入IOC容器的名称
{
registerBeanDefinitions(importingClassMetadata, registry);
}
// 同上,少一个参数
default void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {}
}

实现类

1
2
3
4
5
6
7
public class UserServiceBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar {
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata,BeanDefinitionRegistry registry) {
BeanDefinitionBuilder userService = BeanDefinitionBuilder.rootBeanDefinition(UserServiceImpl.class);
// 这里自行实现,更加灵活
registry.registerBeanDefinition("userService", userService.getBeanDefinition());
}
}

使用方式

1
2
3
@Configuration
@Import(value={UserServiceBeanDefinitionRegistrar.class})
public class Config {}

结合ImportSelector接口

相比较与实现ImportBeanDefinitionRegistrar接口之后直接操作Bean容器来说,使用ImportSelector会更加优雅一些,只需要返回需要注入类的全名即可,也可以同时注入多个Bean,Spring 中EnableAutoConfiguration注解就是用的这种方式。

源码

1
2
3
4
5
6
7
8
9
public interface ImportSelector {
// 返回类全名即可注入
String[] selectImports(AnnotationMetadata importingClassMetadata);
// 传入方法,获取忽略过滤器
@Nullable
default Predicate<String> getExclusionFilter() {
return null;
}
}

实现类

1
2
3
4
5
public class UserServiceImportSelect implements ImportSelector{
public String[] selectImports(AnnotationMetadata importingClassMetadata) {
return new String[]{UserServiceImpl.class.getName()};
}
}

使用方式

1
2
3
@Configuration()
@Import(value={UserServiceImportSelect.class})
public class Config {}

Spring 处理@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
52
53
54
55
56
57
58
59
60
61
62
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 {
this.importStack.push(configClass);
try {
for (SourceClass candidate : importCandidates) {
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);
}
if (selector instanceof DeferredImportSelector) {
this.deferredImportSelectorHandler.handle(configClass, (DeferredImportSelector) selector);
}
else {
String[] importClassNames = selector.selectImports(currentSourceClass.getMetadata());
Collection<SourceClass> importSourceClasses = asSourceClasses(importClassNames, exclusionFilter);
processImports(configClass, currentSourceClass, importSourceClasses, exclusionFilter, false);
}
}
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.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());
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();
}
}
}

总结

最方便的是结合ImportSelector方式,主要作用是使用注解注入BeanIOC容器