Spring学习之@Import
文章目录
注解说明
@Import 注解用于标识多个需要导入的 Component 类,支持导入 @Configuration 类, ImportSelector
与 ImportBeanDefinitionRegistrar 实现,与 AnnotationConfigApplicationContext.register()
方法实现的功能类似。此注解常见的实践方式是标注在 EnableXXXX 注解上,用于开启某些功能,在开启功能时就需要通过 @Import 注解来选择导入哪些类的定义

属性说明
此注解只有一个属性 value,返回 Class[]
,用于标识导入的类

Class类型
@Configuration标识的类
对于不同功能的配置使用多个 @Configuration 标识,由一个类来 Import 另一个 类的配置,来达到复用的效果
|
|
ImportSelector实现类
所有的 ImportSelector
实现都需要实现它的 selectImports 方法,来返回要导入的bean类名称集合
|
|
在 ImportSelector 可以通过Aware或者构造器注入的方式使用 Spring中的容器组件:
- Environment
- BeanFactory
- ClassLoader
- ResourceLoader
DeferredImportSelector
ImportSelector
实现正常情况导入是按配置顺序进行,对于需要延迟导入(在所有导入都完成后)的类可以通过实现 ImportSelector
的子接口 DeferredImportSelector
来操作,这对于实现按条件(Conditional)的导入非常有用
此Selector支持通过配置 group 来实现更灵活的排序与过滤功能
ImportBeanDefinitionRegistrar实现类
Spring提供的低级别的接口来控制Bean的定义,直接操作BeanDefinition实例,处于Bean definition 级别;而使用 @Bean定义方式属于通用的定义方式。接口提供 registerBeanDefinitions() 方法来细粒度控制导入Bean的定义,由方法签名也看出是直接通过 BeanDefinitionRegistry 来直接操作Bean的定义

|
|
常规的 Component 类
导入特定的 Bean 类
|
|
源码分析
核心逻辑位于 context 的 refresh()
阶段,由于此注解通常与 @Configuration 注解一起使用,处理逻辑都是由 ConfigurationClassPostProcessor
类进行处理,此类会委托 ConfigurationClassParser
类进行处理,由此可定位到方法 processImports()

处理 ImportSelectot 实现类
首先实例化 ImportSelector ,在此看到可以使用的 environment, resourceLoader 和 registry
如果 selector 是 ImportSelector
,则获取导入的类名字列表,然后对导入类名字列表分别进行导入操作
处理DeferredImportSelector 实现类
如果 selector 是 DeferredImportSelector
,则调用 DeferredImportSelectorHandler#handle()
方法进行延迟处理,此方法会委托 DeferredImportSelectorGroupingHandler
类进行分组处理,实例化 handler 后,会把 deferrredSelectHolder 存储到 deferredImportSelectors 列表中,在没有显示配置的情况使用的是 DeferredImportSelectorHolder
在 ConfigurationClassParser
解析完所有的 import 类定义后,会调用 DeferredImportSelectorGroupingHandler#process()
方法来处理延迟导入的Bean配置

在此方法会对 deferredImportSelectors 列表中的 selectHolder 进行排序,然后调用按组导入

最终导入的Bean会在 ConfigurationClassParser.DefaultDeferredImportSelectorGroup#process()
中被存入到 imports列表中,然后再对列表进行遍历分别进行导入

处理 ImportBeanDefinitionRegistrar 实现类
ImportBeanDefinitionRegistrar
的实现类的Bean注册没有依赖于组件扫描或者自动配置,而是通过调用 ConfigurationClassBeanDefinitionReader#loadBeanDefinitionsFromRegistrars()
来调用 ImportBeanDefinitionRegistrar 的 registerBeanDefinitions 方法(子类需要实现的方法)来进行注入
总结
Spring的强大在于提供了多种导入配置的方式,分别为:
- 实现
ImportSelector
接口按配置顺序导入 - 实现
DeferredImportSelector
接口在所有配置完成后进行 延迟条件导入 - 更底层的实现
ImportBeanDefinitionRegistrar
接口的方式直接提供BeanDefinitionRegistry
来更细粒度操作Bean的注册