欢迎访问我的 GitHub
这里分类和汇总了欣宸的全部原创(含配套源码):
https://github.com/zq2599/blog_demos
- 在使用 @Import 注解来注册 bean 的时候,Import 注解的值可以是 ImportSelector 或者 DeferredImportSelector 的实现类,spring 容器会实例化这个实现类,并执行其 selectImports 方法,那么问题来了: ImportSelector 和 DeferredImportSelector 的区别在哪里,我们自定义 Imort 逻辑的时候该选择哪个呢? 本文通过分析相关的 spring 源码来查找答案;
全文概览
- 本文由以下几部分组成:
- 看官方文档;
- 分析 spring 源码中对这两个接口的处理;
- 实战验证;
看官方文档
- 先看官方文档看起,我选择了 4.3.9 版本在线文档(这是个 Release 版),地址:https://docs.spring.io/spring/docs/4.3.19.RELEASE/javadoc-api/
- 原文:A variation of ImportSelector that runs after all @Configuration beans have been processed. This type of selector can be particularly useful when the selected imports are @Conditional.Implementations can also extend the Ordered interface or use the Order annotation to indicate a precedence against other DeferredImportSelectors.
- 我的理解:
- DeferredImportSelector 是 ImportSelector 的一个扩展;
- ImportSelector 实例的 selectImports 方法的执行时机,是在 @Configguration 注解中的其他逻辑被处理 之前 ,所谓的其他逻辑,包括对 @ImportResource、@Bean 这些注解的处理(注意,这里只是对 @Bean 修饰的方法的处理,并不是立即调用 @Bean 修饰的方法,这个区别很重要!);
- DeferredImportSelector 实例的 selectImports 方法的执行时机,是在 @Configguration 注解中的其他逻辑被处理 完毕之后 ,所谓的其他逻辑,包括对 @ImportResource、@Bean 这些注解的处理;
- DeferredImportSelector 的实现类可以用 Order 注解,或者实现 Ordered 接口来对 selectImports 的执行顺序排序;
分析 spring 源码中对这两个接口的处理
- 接下来看看源码:
- 在 spring-framework-4.1.8.RELEASE 工程中找到类 ConfigurationClassParser.java,这里面有处理配置类的主要逻辑;
- 找到方法 parse(Set<BeanDefinitionHolder> configCandidates):
public void parse(Set<BeanDefinitionHolder> configCandidates) {
this.deferredImportSelectors = new LinkedList<DeferredImportSelectorHolder>();
//检查每个bean的定义
for (BeanDefinitionHolder holder : configCandidates) {
BeanDefinition bd = holder.getBeanDefinition();
try {
if (bd instanceof AnnotatedBeanDefinition) {
//对于每个有注解的类,都执行方法parse(AnnotationMetadata metadata, String beanName)
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 (Exception ex) {
throw new BeanDefinitionStoreException(
"Failed to parse configuration class [" + bd.getBeanClassName() + "]", ex);
}
}
//最后再处理DeferredImportSelector的实现类
processDeferredImportSelectors();
}
复制代码
- 由以上代码可以大致看出 DeferredImportSelector 的实现类被最后放在 processDeferredImportSelectors 方法中处理,那么前面的 parse(AnnotationMetadata metadata, String beanName)做了些什么呢?继续看;
- 展开方法 parse(AnnotationMetadata metadata, String beanName)里面,是执行 processConfigurationClass 方法;
- 再展开 processConfigurationClass 方法,看到核心逻辑是调用 doProcessConfigurationClass 方法,展开看看:
protected final SourceClass doProcessConfigurationClass(ConfigurationClass configClass, SourceClass sourceClass) throws IOException {
//为了聚焦Import相关处理,此处略去部分不相关代码,不在这里展示了
...
...
// 处理@Import注解
processImports(configClass, sourceClass, getImports(sourceClass), true);
// 处理@ImportResource注解
if (sourceClass.getMetadata().isAnnotated(ImportResource.class.getName())) {
AnnotationAttributes importResource = AnnotationConfig