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()
处理 ImportSelector 实现类
首先实例化 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 方法(子类需要实现的方法)来进行注入

处理其它类型的导入
如果要导入的类不是 ImportSelector 及其实现类和 ImportBeanDefinitionRegistrar 的实现类,则会按照 @Configuration 类方式进行导入,Spring会调用 候选类的 asConfigClass() 方法将其包装成 ConfigurationClass 返回然后来进行处理,这样就就使用 在 @Import 注解中直接导入一个实体Bean成为了可能
ConfigurationClass 类是Spring内部用于表示一个扁平化的用户定义的 @Configuration 配置类的模型对象
总结
Spring的强大在于提供了多种导入配置的方式,分别为:
- 实现
ImportSelector接口按配置顺序导入 - 实现
DeferredImportSelector接口在所有配置完成后进行 延迟条件导入 - 更底层的实现
ImportBeanDefinitionRegistrar接口的方式直接提供BeanDefinitionRegistry来更细粒度操作Bean的注册