注解说明

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

属性说明

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

Class类型

@Configuration标识的类

对于不同功能的配置使用多个 @Configuration 标识,由一个类来 Import 另一个 类的配置,来达到复用的效果

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
@Configuration
public class MyConfig2 {

    @Bean
    public MyBeanD myBeanD() {
        return new MyBeanD();
    }
}

@Configuration
@Import({MyConfig2.class})
public class MyConfig {
}

ImportSelector实现类

所有的 ImportSelector 实现都需要实现它的 selectImports 方法,来返回要导入的bean类名称集合

1
2
3
4
5
6
7
public class MyImportSelector implements ImportSelector {

    @Override
    public String[] selectImports(AnnotationMetadata importingClassMetadata) {
        return new String[]{MyBeanA.class.getName()};
    }
}

在 ImportSelector 可以通过Aware或者构造器注入的方式使用 Spring中的容器组件:

  1. Environment
  2. BeanFactory
  3. ClassLoader
  4. ResourceLoader

DeferredImportSelector

ImportSelector 实现正常情况导入是按配置顺序进行,对于需要延迟导入(在所有导入都完成后)的类可以通过实现 ImportSelector 的子接口 DeferredImportSelector 来操作,这对于实现按条件(Conditional)的导入非常有用

此Selector支持通过配置 group 来实现更灵活的排序与过滤功能

ImportBeanDefinitionRegistrar实现类

Spring提供的低级别的接口来控制Bean的定义,直接操作BeanDefinition实例,处于Bean definition 级别;而使用 @Bean定义方式属于通用的定义方式。接口提供 registerBeanDefinitions() 方法来细粒度控制导入Bean的定义,由方法签名也看出是直接通过 BeanDefinitionRegistry 来直接操作Bean的定义

1
2
3
4
5
6
7
8
public class MyImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar {

    @Override
    public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
        RootBeanDefinition beanDefinition = new RootBeanDefinition(MyBeanC.class);
        registry.registerBeanDefinition(MyBeanC.class.getName(), beanDefinition);
    }
}

常规的 Component 类

导入特定的 Bean 类

1
2
3
@Import(MyBean.class)
public class MyComponentConfig {
}

源码分析

核心逻辑位于 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的强大在于提供了多种导入配置的方式,分别为:

  1. 实现 ImportSelector 接口按配置顺序导入
  2. 实现 DeferredImportSelector 接口在所有配置完成后进行 延迟条件导入
  3. 更底层的实现 ImportBeanDefinitionRegistrar 接口的方式直接提供 BeanDefinitionRegistry 来更细粒度操作Bean的注册