@Import注解的作用
说到@Import注解,必须要说的是下面这两个类
ImportSelector接口对应的实现方法中,需要返回一个数组,数组中,是要注入到spring容器中的class对应的全类名
ImportBeanDefinitionRegistrar接口的实现方法中,会提供BeanDefinitionRegistry对象,我们可以在方法中通过该对象自己注入到beanDefinitionMap中一个beanDefinition对象
这是这两个类的作用
在spring源码中,@Import注解是使用最多的,一点也不为过,其实在大部分的框架中,会看到每个框架会自定义好多注解,这些注解中,有一大部分都是利用了@Import注解来完成的,并且,通过@Import注解,注入的,一般都是ImportSelector或者是ImportBeanDefinitionRegistrar的实现类
关于这两个扩展点的原理,在前面的博客中spring源码:@Import注解
,有记录过,所以,就不做过多的解释,大致再总结一下吧
1、在spring源码中,将一个class对象转换成一个spring容器所能接收的bean对象,首先要先将class对象转换为beanDefinition对象,在转换过程中,通常是通过@ComponentScan注解来完成扫描,转换的
2、但是需要考虑的一个点:有可能我们注入的bean是ImportSelector或者ImportBeanDefinitionRegistrar的实现类,而ImportSelector所注入的类中,有可能还有ImportSelector或者是ImportBeanDefinitionRegistrar的实现类,所以,在源码中,会进行一个递归的判断,一直解析到当前bean是一个普普通通的bean,然后将所有的bean存到一个集合中
3、需要注意的是,这时候,通过@Import引入的ImportSelector和ImportBeanDefinitionRegistrar实现类中,返回的bean还是一个普通的class对象,并没有转换为beanDefinition,spring在解析完成之后,会统一对这两个实现类进行处理
4、所谓的统一处理,就是按照当前是importBeanDefinitionRegistrar还是ImportSelector,还是@Bean注入的,去处理,转换为beanDefinition,然后存入到beanDefinitionMap中
应用
接下来主要说应用,其实对于@Import注解,
1、我们可以直接通过@Import引入一个普通的bean
2、也可以引入一个ImportSelector的实现类
3、也可以引入一个ImportBeanDefinitionRegistrar的实现类
ImportBeanDefinitionRegistrar
@Configuration
@ComponentScan("com.spring.study.importbeandefinitionregistrar")
@Import({MyImportBeanDefinitionRegistrar.class,ImportTestBean.class})
public class ImportConfig {
}
public class ImportTestBean {
}
public class MyImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar {
@Override
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
System.out.println("自己手动注入一个bean");
BeanDefinitionBuilder beanDefinitionBuilder = BeanDefinitionBuilder.genericBeanDefinition(OrderBean.class);
registry.registerBeanDefinition("orderBean", beanDefinitionBuilder.getBeanDefinition());
}
}
public class OrderBean {
}
public class TestImportBeanDefinitionRegistrar {
public static void main(String[] args) {
AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext(ImportConfig.class);
System.out.println(ac.getBean(OrderBean.class));
System.out.println(ac.getBean(ImportTestBean.class));
}
}
最终的打印结果
自己手动注入一个bean
18:49:04.903 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'org.springframework.context.event.internalEventListenerProcessor'
18:49:04.906 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'org.springframework.context.event.internalEventListenerFactory'
18:49:04.907 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'org.springframework.context.annotation.internalAutowiredAnnotationProcessor'
18:49:04.909 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'org.springframework.context.annotation.internalCommonAnnotationProcessor'
18:49:04.927 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'importConfig'
18:49:04.936 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'com.spring.study.importbeandefinitionregistrar.ImportTestBean'
18:49:04.936 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'orderBean'
com.spring.study.importbeandefinitionregistrar.OrderBean@43301423
com.spring.study.importbeandefinitionregistrar.ImportTestBean@2f112965
这里的@Import注解注入了两个class,一个是普通的bean,一个是importBeanDefinitionRegistrar的实现类
所以,ImportBeanDefinitionRegistrar接口的作用就是将BeanDefinitionRegistry交给程序员,由程序员自己去决定要做的业务逻辑
ImportSelector
public class MyImportSelector implements ImportSelector {
@Override
public String[] selectImports(AnnotationMetadata annotationMetadata) {
return new String[]{"com.spring.study.importselector.OperChannelEntity","com.spring.study.importselector.UserBean"};
}
}
importSelector就不贴太多的代码了,只要把这个bean,通过@Import注解引入,spring就会帮我们注入OperChannelEntiry和UserBean这两个class
springboot的自动注入,就是用到了这个点,实现了ImportSelector,然后将要自动注入的bean,获取到其全类名,然后放入到返回的数组中即可