• @Import、@ImportAutoConfiguration 到底有什么区别?


     

    背景

    当我需要在一个Configuration配置类中导入另一个Configuration配置类时,我们可以使用 @Import注解 或者 @ImportAutoConfiguration ,如下两图:
    经过试验证明,从效果上来看,这两种方式都能很好的工作,额外的配置类都被正确的加载了,并且都能触发 ImportAware 扩展点,那么这两个注解到底有啥区别呢?
     

    解析

    针对背景中的问题,我在网上搜索良久都没有得到明确的满意答案,还是决定通过源码来窥探一下其中奥秘。
    如果时间紧任务急的同学也可以直接看最后的总结

     

    原理剖析

    通过两个注解的元信息,我们可以看到@ImportAutoConfiguration 注解中继承了一个@Import 注解。
     
    所以想要搞清楚这两者的区别,我们必须先搞明白 Import 注解是个什么东西。
     

    @Import

    先贴一个Import注解类的注释信息 (附上有道翻译版本。。)
    表示要导入的一个或多个@Configuration类。
    提供与Spring XML中的<import/>元素等价的功能。允许导入@Configuration类、ImportSelector和ImportBeanDefinitionRegistrar实现,以及常规的组件类(从4.2;类似于AnnotationConfigApplicationContext.register)。
    在导入的@Configuration类中声明的@Bean定义应该通过@Autowired注入来访问。可以自动连接bean本身,也可以自动连接声明该bean的配置类实例。后一种方法允许在@Configuration类方法之间进行显式的、ide友好的导航。
    可以在类级别声明,也可以作为元注释声明。
    如果需要导入XML或其他non-@Configuration bean定义资源,则使用@ImportResource注释。
     
    大概意思就是说,Import 注解主要是用来替代 Spring XML 中的<import/>标签的,我们来看下<import/>标签又是干嘛的呢?
    根据官方文档的说法,import是用来解决配置混乱的问题的,它支持我们将需要声明的bean进行分类并写入多个xml配置文件中,并通过import标签将这些配置文件整合到一起,是配置文件逻辑更加清晰,也更加优雅。
     
    大家知道@Configuration类本质上就是一个xml配置文件的替代品,现在我们知道了,@Import 注解的初衷就是使我们可以在配置类中导入其他配置类,并最终将这些配置类整合在一起进行处理。
     
    除此之外,@Import注解的注释中写了,除了导入@Configuration配置类以外,它还能导入ImportSelector 和 ImportBeanDefinitionRegistrar 实现类,那么 ImportSelector和ImportBeanDefinitionRegistrar 是什么东西呢。
     
    正如上面图片所示的那样,直接在 Import 注解中声明配置类的方式是最常用的姿势,不过这是有缺陷的,比如:
    1. 导入的配置类集合是固定的,无法根据实际场景进行选择性的导入
    2. 由于Import注解的value只接受 Class 类型的,意味着所导入的类必须在当前模块或所依赖的下游模块中,无法导入一个上游 或 第三方的配置类(类似SPI的机制,虽然这不是很好理解,也很少会有这种需求。。。)
     
    ImportSelector 就可以解决上面的两个缺陷,它根据导入的ImportSelector实现类所返回的值作为需要导入的 配置类集合,并对这些配置类进行加载。
    我们考虑这样一个需求
    如果应用配置中指定了使用1号配置类时,加载 MyOtherConfiguration1.java,否则默认加载 MyOtherConfiguration2.java
    针对这个场景,我们可以通过以下配置方式进行实现:
     
    相比 ImportSelector 这种返回类全限定名集合来指定需要加载的配置类的方式,ImportBeanDefinitionRegistrar 则更加直接,它的接口中额外提供了 BeanDefinitionRegistry 参数,意味着我们可以在 ImportBeanDefinitionRegistrar 的实现类中自主的进行 Bean的注册,而不是返回一个类名或 类对象。
    我们依然考虑这样一个需求
    如果应用配置中指定了使用1号配置类时,加载 MyOtherConfiguration1.java,否则默认加载 MyOtherConfiguration2.java
    针对这个场景,我们可以通过以下配置方式进行实现:
     
    至此,我们算是搞清楚了 @Import 注解的工作模式,关于它的工作机制与原理,如果大家感兴趣,可以对源码进行窥探,相关逻辑入口在 org.springframework.context.annotation.ConfigurationClassParser:302行
     

    @ImportAutoConfiguration

    接下来轮到 @ImportAutoConfiguration 注解了
    定睛一看,@ImportAutoConfiguration 继承了 @Import 注解,并导入了一个 ImportSelector 的实现类 ImportAutoConfigurationImportSelector。
    根据我们刚才的了解
    Import注解 根据导入的ImportSelector实现类所返回的值作为需要导入的 配置类集合,并对这些配置类进行加载。
    我们可以猜到 ImportAutoConfigurationImportSelector 肯定是根据某种逻辑返回了需要被导入的配置类集合。
    我们发现 ImportAutoConfigurationImportSelector 并没有实现 selectImports 接口,这个接口是由它的父类 AutoConfigurationImportSelector 进行实现的。
    可以看到它是调用 getAutoConfigurationEntry 获取配置类集合,继续看 getAutoConfigurationEntry 的逻辑
    可以看到它调用了 getCandidateConfigurations 方法获取的配置类集合,就是这个方法被 ImportAutoConfigurationImportSelector 重写了逻辑,如下:
    简单解释一下它的逻辑
    1. 先获取当前配置类上的 ImportAutoConfiguration 注解信息
    2. 如果 ImportAutoConfiguration 注解中指定了classes(或value) 属性值,那么直接返回 classes 的值
    3. 如果未配置 classes(或value) 属性值,从 spring.factories 文件中读取key为当前配置类名的结果
     
    配合一个案例场景可能更加好理解
    在 MyAutoConfiguration 配置类中 导入 MyOtherAutoConfiguration
    通过 @ImportAutoConfiguration 注解可以有两种方式实现这个需求
    方式一:直接在注解中指定
    方式二:注解中不指定classes或value,并在 spring.factories 中指定目标配置类
     

    总结

    相同点

    1. Import 与 ImportAutoConfiguration 注解都可以通过 value 属性指定需要导入的@Configuration配置类
    2. Import 与 ImportAutoConfiguration 注解都支持通过 value 属性配置 ImportSelector类、ImportBeanDefinitionRegistrar类 的方式来间接导入所需的配置类

    不同点

    1. @Import 注解只能通过 value 属性值进行导入
    2. @ImportAutoConfiguration 注解的 value 属性值是可选的,当value属性值未指定时,会尝试从 spring.factories 文件中读取相应的配置作为需要导入的配置类集合
     

    彩蛋

    你知道 @ImportAutoConfiguration 和 @EnableAutoConfiguration 有什么区别吗?
    可以看到很熟悉的一幕,@EnableAutoConfiguration注解继承了 @Import 注解并加载了一个
    AutoConfigurationImportSelector,这不就是刚刚 ImportAutoConfigurationImportSelector 的父类吗?
    我们看下没有被 ImportAutoConfigurationImportSelector 重写过的逻辑是怎么样的
    它直接去 spring.factories 配置文件中寻找 EnableAutoConfiguration 配置项来作为配置类集合进行加载,如下:
     
    那 @EnableAutoConfiguration 在哪里被使用的呢?
    @SpringBootApplication 注解继承了 EnableAutoConfiguration 注解。。。
     
    那么。。好像发现了 SpringBoot 自动装配的秘密呢 ~~
     
     
  • 相关阅读:
    自定义CoordinatorLayout Behavior 隐藏Footer View
    开发错误记录10: Butterknife8.1.0 提示NullPointerException空指针
    要练习的项目
    2016年GitHub 排名前 100 的安卓、iOS项目简介(收藏)
    Android应用崩溃后异常捕获并重启并写入日志
    使用过的第三方框架汇总
    Eclipse导入 appcompat,design兼容包
    沉浸式模式与沉浸式状态栏
    开发错误记录9:Application无法跳转到Activity
    Android获取图片资源的4种方式
  • 原文地址:https://www.cnblogs.com/imyjy/p/16092825.html
Copyright © 2020-2023  润新知