ImportSelector 与 DeferredImportSelector 的区别(spring4)

欢迎访问我的 GitHub

这里分类和汇总了欣宸的全部原创(含配套源码):
https://github.com/zq2599/blog_demos

  • 在使用 @Import 注解来注册 bean 的时候,Import 注解的值可以是 ImportSelector 或者 DeferredImportSelector 的实现类,spring 容器会实例化这个实现类,并执行其 selectImports 方法,那么问题来了: ImportSelector 和 DeferredImportSelector 的区别在哪里,我们自定义 Imort 逻辑的时候该选择哪个呢? 本文通过分析相关的 spring 源码来查找答案;

全文概览

  • 本文由以下几部分组成:
  1. 看官方文档;
  2. 分析 spring 源码中对这两个接口的处理;
  3. 实战验证;

看官方文档

  • 先看官方文档看起,我选择了 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.
  • 我的理解:
  1. DeferredImportSelector 是 ImportSelector 的一个扩展;
  2. ImportSelector 实例的 selectImports 方法的执行时机,是在 @Configguration 注解中的其他逻辑被处理 之前 ,所谓的其他逻辑,包括对 @ImportResource、@Bean 这些注解的处理(注意,这里只是对 @Bean 修饰的方法的处理,并不是立即调用 @Bean 修饰的方法,这个区别很重要!);
  3. DeferredImportSelector 实例的 selectImports 方法的执行时机,是在 @Configguration 注解中的其他逻辑被处理 完毕之后 ,所谓的其他逻辑,包括对 @ImportResource、@Bean 这些注解的处理;
  4. 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 = AnnotationConfigU
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值