一:简述
@Import注解是Spring中比较核心的注解,它的功能很强大,特别是在SpringBoot中,@Import注解使用的地方非常多,无论是@EnableXX类型的注解,还是自动装配都和@Import注解脱不开关系。今天就和大家聊聊它的作用以及原理。
二:@Import注解的作用
@Import功能和Spring XML配置文件里面的<Import>
标签一样,也就是用来把配置类或者一些需要加载的类加入到Spring IoC容器中。
而导入的类可以分为三种情况:
@Component
@Import(User.class)
public class ImportTest {
}
@Data
public class User {
private Integer id;
private String username;
private String password;
}
这种情况下,@Import注解的作用就是将类加入到IoC容器中
ImportSelector
接口或 DeferredImportSelector
接口的实现类ImportSelector接口:
public class ImportSeletorTest implements ImportSelector {
@Override
public String[] selectImports(AnnotationMetadata importingClassMetadata) {
return new String[]{"com.example.User"};
}
}
@Component
@Import(ImportSeletorTest.class)
public class ImportTest {
}
package com.example;
public class User {
private Integer id;
private String username;
private String password;
}
DeferredImportSelector接口:
public class DeferredImportTest implements DeferredImportSelector {
@Override
public String[] selectImports(AnnotationMetadata importingClassMetadata) {
return null;
}
@Override
public Class<? extends Group> getImportGroup() {
return TestGroup.class;
}
private static class TestGroup implements Group {
List<Entry> entries = new ArrayList<>();
@Override
public void process(AnnotationMetadata metadata, DeferredImportSelector selector) {
Entry entry = new Entry(metadata,"com.example.User");
entries.add(entry);
}
@Override
public Iterable<Entry> selectImports() {
return entries;
}
}
}
package com.example;
public class User {
private Integer id;
private String username;
private String password;
}
这种情况下我们可以自定义逻辑,根据我们的业务逻辑判断导入一些类到IoC容器中。
ImportBeanDefinitionRegistrar
接口的实现类public class RegistrarTest implements ImportBeanDefinitionRegistrar {
@Override
public void registerBeanDefinitions(AnnotationMetadata metadata, BeanDefinitionRegistry registry) {
registry.registerBeanDefinition("user",new RootBeanDefinition(User.class));
}
}
@Component
@Import(RegistrarTest.class)
public class ImportTest {
}
package com.example;
public class User {
private Integer id;
private String username;
private String password;
}
如果@Import注解导入的类是ImportBeanDefinitionRegistrar的实现类,那么可以利用registerBeanDefinitions()方法将bean注入到IoC容器中。
注:DeferredImportSelector
接口是ImportSelector
接口的子接口,它们的区别在下文进行分析
三:源码分析
在ConfigurationClassPostProcessor这个处理器中,它实现了BeanDefinitionRegistryPostProcessor接口,所以对bean初始化之前会调用postProcessBeanDefinitionRegistry()方法,在postProcessBeanDefinitionRegistry()方法中对@Component,@ComponentScan,@Import,@ImportResource等注解进行了处理。调用路径是这样的:
对于@Import注解的处理是在ConfigurationClassParser类的processImports()方法中,所以我们重点分析processImports()方法。
protected final SourceClass doProcessConfigurationClass(
ConfigurationClass configClass, SourceClass sourceClass, Predicate<String> filter)
throws IOException {
......
//由于篇幅原因前面代码省略 重点看processImports()方法
//处理@Import注解
// Process any @Import annotations
processImports(configClass, sourceClass, getImports(sourceClass), filter, true);
//省略
.....
}
流程图:
1. 如果是ImportSelector类型
a. 进一步判断是否是DeferredImportSelector类型,如果是,加入到deferredImportSelectors里面最后处理,在parse()方法,最后一行才调用deferredImportSelectorHandler.process()方法进行处理。最后会调用process()方法和group的electImports()获取到需要导入的类,然后再次调用processImports方法。
b. 如果不是DeferredImportSelector类型,那就调用selectImports方法,获取到所有的需要注入的类,这时再次调用processImports方法。
2. 如果是 ImportBeanDefinitionRegistrar 类型,这里也是 先实例一个对象,然后加入到 importBeanDefinitionRegistrars 里面,后续会在ConfigurationClassBeanDefinitionReader这个类里面的loadBeanDefinitionsFromRegistrars方法处理的
3. 如果既不是ImportSelector类型也不是ImportBeanDefinitionRegistrar类型,就再调用processConfigurationClass()方法进行处理。
源码:
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)) {
//处理ImportSelector的实现类
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()类型调用deferredImportSelectorHandler的handle方法
if (selector instanceof DeferredImportSelector) {
this.deferredImportSelectorHandler.handle(configClass, (DeferredImportSelector) selector);
}
else {
//调用selectImports()方法获取需要导入的类 排除需要排除的类之后 递归调用一下processImports
String[] importClassNames = selector.selectImports(currentSourceClass.getMetadata());
Collection<SourceClass> importSourceClasses = asSourceClasses(importClassNames, exclusionFilter);
processImports(configClass, currentSourceClass, importSourceClasses, exclusionFilter, false);
}
}
// 如果是导入实现了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);
configClass.addImportBeanDefinitionRegistrar(registrar, currentSourceClass.getMetadata());
}
else {
this.importStack.registerImport(
currentSourceClass.getMetadata(), candidate.getMetadata().getClassName());
//对于配置类和普通类调用processConfigurationClass进行处理
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();
}
}
}
四:DeferredImportSelector和ImportSelector的区别
根据前文我们已经知道了DeferredImportSelector是ImportSelector的子接口,它们二者最主要的区别在于DeferredImportSelector接口的实现类会在最后进行处理(在@Bean,@ImportResource等注解之后)。在processImports()方法处理DeferredImportSelector方法的时候会调用 deferredImportSelectorHandler.handle()
进行处理。我们可以看到deferredImportSelectors在类中已经new了,所以第一次进来肯定不为null,所以只会先放入到deferredImportSelectors,等之后处理。
public void handle(ConfigurationClass configClass, DeferredImportSelector importSelector) {
DeferredImportSelectorHolder holder = new DeferredImportSelectorHolder(configClass, importSelector);
//第一次进来肯定不为null 只有在调用deferredImportSelectorHandler.process()之后才会为null
if (this.deferredImportSelectors == null) {
DeferredImportSelectorGroupingHandler handler = new DeferredImportSelectorGroupingHandler();
handler.register(holder);
handler.processGroupImports();
}
else {
//放入到deferredImportSelectors中
this.deferredImportSelectors.add(holder);
}
}
在parse()方法中,我们可以明显看到DeferredImportSelector是最后处理。
public void parse(Set<BeanDefinitionHolder> configCandidates) {
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导入的类
this.deferredImportSelectorHandler.process();
}
最后分析下DeferredImportSelector类的处理,它首先会获取DeferredImportSelector类的getImportGroup()返回的Group,如果返回的Group是null(默认实现是返回null),就会使用默认的Group(也就是DefaultDeferredImportSelectorGroup),然后会分别调用Group的process()方法和selectImports()方法收集需要导入的类,最后会调用processImports()方法将收集的类导入到Spring容器中。
注:SpringBoot的自动装配和DeferredImportSelector类是脱不开关系的,我们理解了DeferredImportSelector,那么自动装配的原理也就懂了一大半了。
源码:
deferredImportSelectorHandler的process()方法负责处理导入DeferredImportSelector类的处理逻辑,首先循环收集的DeferredImportSelectorHolder,调用它的register方法将DeferredImportSelector进行分组,然后调用processGroupImports()方法分组进行处理。
process()
public void process() {
List<DeferredImportSelectorHolder> deferredImports = this.deferredImportSelectors;
//将deferredImportSelectors设置为null 说明已经到了进行deferredImportSelectors处理的阶段了
// 下次就不需要在延迟处理了
this.deferredImportSelectors = null;
try {
if (deferredImports != null) {
DeferredImportSelectorGroupingHandler handler = new DeferredImportSelectorGroupingHandler();
deferredImports.sort(DEFERRED_IMPORT_COMPARATOR);
//循环调用register方法
deferredImports.forEach(handler::register);
handler.processGroupImports();
}
}
finally {
this.deferredImportSelectors = new ArrayList<>();
}
}
}
register()
register()方法的作用是根据DeferredImportSelector的getImportSelector()方法将收集的DeferredImportSelector进行分组,并且保存在DeferredImportSelectorGrouping中。
public void register(DeferredImportSelectorHolder deferredImport) {
//获取Group
Class<? extends Group> group = deferredImport.getImportSelector().getImportGroup();
//如果getImportGroup()方法返回的Group为null 那么就以DeferredImportSelectorHolder为key 并且用默认的DeferredImportSelectorGrouping为value
DeferredImportSelectorGrouping grouping = this.groupings.computeIfAbsent(
(group != null ? group : deferredImport),
key -> new DeferredImportSelectorGrouping(createGroup(group)));
grouping.add(deferredImport);
//将需要导入的类加入到configurationClasses中
this.configurationClasses.put(deferredImport.getConfigurationClass().getMetadata(),
deferredImport.getConfigurationClass());
}
processGroupImports()
processGroupImports()方法作用是根据getImports()方法获取到需要导入的类,然后再次通过processImports()方法将需要导入的类导入到Spring容器中。
public void processGroupImports() {
for (DeferredImportSelectorGrouping grouping : this.groupings.values()) {
Predicate<String> exclusionFilter = grouping.getCandidateFilter();
//循环getImports()返回的Entry 获取需要导入的类
grouping.getImports().forEach(entry -> {
ConfigurationClass configurationClass = this.configurationClasses.get(entry.getMetadata());
try {
//将需要导入的类再次通过processImports()方法进行处理
processImports(configurationClass, asSourceClass(configurationClass, exclusionFilter),
Collections.singleton(asSourceClass(entry.getImportClassName(), exclusionFilter)),
exclusionFilter, false);
}
catch (BeanDefinitionStoreException ex) {
throw ex;
}
catch (Throwable ex) {
throw new BeanDefinitionStoreException(
"Failed to process import candidates for configuration class [" +
configurationClass.getMetadata().getClassName() + "]", ex);
}
});
}
}
getImports()
getImports()方法通过Group的process和selectImports()方法收集需要导入的类。
public Iterable<Group.Entry> getImports() {
//循环所有的deferredImports 调用Group的process()方法
for (DeferredImportSelectorHolder deferredImport : this.deferredImports) {
this.group.process(deferredImport.getConfigurationClass().getMetadata(),
deferredImport.getImportSelector());
}
//调用Group的selectImports() 并且返回收集到的Entry
return this.group.selectImports();
}
默认的Group:
DefaultDeferredImportSelectorGroup
private static class DefaultDeferredImportSelectorGroup implements Group {
private final List<Entry> imports = new ArrayList<>();
@Override
public void process(AnnotationMetadata metadata, DeferredImportSelector selector) {
//调用ImportSelector的selectImports()方法收集需要导入的类
for (String importClassName : selector.selectImports(metadata)) {
this.imports.add(new Entry(metadata, importClassName));
}
}
@Override
public Iterable<Entry> selectImports() {
return this.imports;
}
}