一、导言
在spring框架下做开发时,会给容器中导入组件,通常我们给容器中注入组件的方式,可以通过Spring的xml配置方式,也可以通过注解,如@Component
等,也可以通过java配置类的方式给容器中导入,@Import也是常见的导入注解(组件如类实例),可以用来动态创建bean。
二、使用
1. 从spring、springboot的很多Enable前缀的注解可以看出,Enable注解使用了Import注解;
2. 三种Import注解用法;
3. spring源码,揭示Import注解的工作原理;
4. 实战通过Import注解动态创建bean实例;
1、Enable前缀的注解
有很多注解都以Enable为前缀,例如配置调度的注解EnableScheduling,其源码如下 :
从以上代码可见,@Import(SchedulingConfiguration.class),通过此注解spring容器会创建SchedulingConfiguration实例。
再如如EnableBatchProcessing、EnableCaching、EnableDiscoveryClient等,也都是通过Import来生效的,这种方式值得我们学习,在公司的通用组件、通用模块等开发中,也能用类似方式来对bean实例导入。
2、3种使用
在@Import注解的参数中可以填写类名,例如@Import(Abc.class),根据类Abc的不同类型,spring容器有以下四种处理方式:
1. 如果Abc类实现了ImportSelector接口,spring容器就会实例化Abc类,并且调用其selectImports方法;
2. 如果Abc类实现了ImportBeanDefinitionRegistrar接口,spring容器就会实例化Abc类,并且调用其registerBeanDefinitions方法;
3. 如果Abc没有实现ImportSelector、DeferredImportSelector、ImportBeanDefinitionRegistrar等其中的任何一个,spring容器就会实例化Abc类。
2.1、直接导入,适用于少数类实例导入spring容器,一般在Enable***注解使用非常多。
@Import({A.class, B.class})
2.2、如果组件很多,我们也可以结合ImportSelector来使用
public class MyImportSelector implements ImportSelector {
public String[] selectImports(AnnotationMetadata importingClassMetadata) {
return new String[]{"com.test.entity.A","com.test.entity.B"};
}
}
这是个导入选择器,从这个方法名 selectImports 就可以看出,是选择性的导入的意思,所以在这个方法中,我们是可以通过编写不同的逻辑,来返回我们需要导入的组件,上面自定义的选择导入器,只是为了演示,所以没有具体的条件判断等,可自行扩展,返回需要导入的组件A和B,然后将这个类加入到@Import注解的参数中,如下代码
@Import({E.class, F.class,MyImportSelector.class}
2.3、实现接口ImportBeanDefinitionRegistrar
ImportBeanDefinitionRegistrar与ImportSelector的使用大致相同,它是接口,我们只需实现它,并将它作为参数,放在@Import中即可。
2.3.1. 创建MyImportBeanDefinitionRegistrar类
public class MyImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar {
com.test.entity.C
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
boolean definition = registry.containsBeanDefinition("");
com.test.entity.D
boolean definition2 = registry.containsBeanDefinition("");
if(definition && definition2){
//指定Bean定义信息
RootBeanDefinition beanDefinition = new RootBeanDefinition(R.class);
//注册一个Bean,指定bean名
registry.registerBeanDefinition("R", beanDefinition);
}
}
2.3.2、使用import ,就可以把R的实例导入spring容器
@Import({E.class, F.class,MyImportSelector.class,MyImportBeanDefinitionRegistrar.class})
2.4、和ImportSources的区别
@Import注解是引入带有@Configuration的java类。
@ImportResource是引入spring配置文件.xml