springmvc实战技巧解析(十五)@Import注解全解析

举报
小鲍侃java 发表于 2021/09/11 00:58:04 2021/09/11
【摘要】 写在前面 向spring中注册组件或者叫javaBean是使用spring的功能的前提条件。而且spring也提供了很多种方式,让我们可以将普通的javaBean注册到spring容器中,比如前一篇文章Spring Framework 组件注册 之 @Component中写的利用@Component注解将普通的javaBean注...

写在前面

向spring中注册组件或者叫javaBean是使用spring的功能的前提条件。而且spring也提供了很多种方式,让我们可以将普通的javaBean注册到spring容器中,比如前一篇文章Spring Framework 组件注册 之 @Component中写的利用@Component注解将普通的javaBean注册到容器中,本文说的@Import注解也是spring Framework提供的将普通javaBean注册到容器中,以及后续文章会说的@Configuration,FactoryBean等方式。

@Import 注册普通Bean

使用@Import注册一个普通Bean,只需要在@Import注解中指定待注册Bean的class即可


  
  1. /**
  2. * 使用Import注解,注册一个普通的Bean
  3. */
  4. @Data
  5. public class TestImport {
  6. private String id = "@Import";
  7. }
  8. 复制代码

在spring启动引导类中,添加@Import注解


  
  1. /**
  2. * spring 容器启动引导类
  3. */
  4. @Import(TestImport.class)
  5. public class TestImportBootstrap {
  6. public static void main(String[] args) {
  7. AnnotationConfigApplicationContext applicationContext =
  8. new AnnotationConfigApplicationContext(TestImportBootstrap.class);
  9. System.out.println("context id : " + applicationContext.getId());
  10. String[] beanNames = applicationContext.getBeanNamesForType(TestImport.class);
  11. System.out.println("Bean Name is : " + Arrays.toString(beanNames));
  12. TestImport bean = applicationContext.getBean(TestImport.class);
  13. System.out.println("TestImport bean : " + bean);
  14. applicationContext.close();
  15. }
  16. }
  17. 复制代码

spring容器启动后,控制台打印的结果:

context id : org.springframework.context.annotation.AnnotationConfigApplicationContext@21b8d17c Bean Name is : [com.spring.study.ioc.register.TestImport] TestImport bean : TestImport(id=@Import)

通过简单使用@Import注解,便可以将一个普通的javaBean注册到spring容器中。并且我们可以看到,通过@Import注解默认注册的组件名称为该javaBean的全类名

@Import 导入 配置类

使用@Import注解导入配置类,就会将配置类中的所有组件注册到spring容器中。在spring中,并不是@Configuration标注的类才是配置类,但是被@Configuration标注的类会被生成代理对象,spring注入时与不使用@Configuration注解有很大区别,后续会单独说明此处内容,本文不在赘述。


  
  1. /**
  2. * spring组件配置类
  3. */
  4. //@Configuration 使用@Import导入时,此注解可以不加
  5. public class TestConfiguration {
  6. @Bean
  7. public TestImport testImport() {
  8. return new TestImport();
  9. }
  10. @Bean
  11. public TestImport testImport2() {
  12. return new TestImport();
  13. }
  14. }
  15. 复制代码

@Import注解中指定待导入的配置类


  
  1. /**
  2. * spring 容器启动引导类
  3. */
  4. @Import(TestConfiguration.class)
  5. public class TestImportBootstrap {
  6. public static void main(String[] args) {
  7. AnnotationConfigApplicationContext applicationContext =
  8. new AnnotationConfigApplicationContext(TestImportBootstrap.class);
  9. System.out.println("context id : " + applicationContext.getId());
  10. String[] beanNames = applicationContext.getBeanNamesForType(TestImport.class);
  11. System.out.println("Bean Name is : " + Arrays.toString(beanNames));
  12. TestImport bean = (TestImport) applicationContext.getBean("testImport");
  13. System.out.println("TestImport bean : " + bean);
  14. applicationContext.close();
  15. }
  16. }
  17. 复制代码

spring容器启动后,配置类中的注解同样会被注册到spring容器中:

context id : org.springframework.context.annotation.AnnotationConfigApplicationContext@21b8d17c Bean Name is : [testImport, testImport2] TestImport bean : TestImport(id=@Import)

由结果可以看出,此时注册的组件名称即为配置类中指定的组件名称,并且通过配置类,可以一次导入多个组件。

@Import 通过ImportSelector 注册

ImportSelector接口中只定义了一个接口selectImports,通过此接口返回需要注册的JavaBean的全类名数组,在使用@Import导入时,会将接口返回的所有类注册到spring容器中


  
  1. /**
  2. * 通过 ImportSelector 接口注册组件
  3. */
  4. @Data
  5. public class TestSelector {
  6. private String id = "@Import:ImportSelector";
  7. }
  8. 复制代码

自定义实现ImportSelector接口


  
  1. /**
  2. * 自定义组件选择器,通过返回需要注册的bean的全类名,进行快速的在IOC容器中注册组件
  3. */
  4. public class CustomImportSelector implements ImportSelector {
  5. /**
  6. * @param importingClassMetadata 标注了@Import配置类上面所有的注解信息
  7. */
  8. public String[] selectImports(AnnotationMetadata importingClassMetadata) {
  9. return new String[]{TestSelector.class.getName()};
  10. }
  11. }
  12. 复制代码

@Import注解中指定ImportSelector实现类


  
  1. /**
  2. * spring 容器启动引导类
  3. */
  4. @Import(CustomImportSelector.class)
  5. public class TestImportBootstrap {
  6. public static void main(String[] args) {
  7. AnnotationConfigApplicationContext applicationContext =
  8. new AnnotationConfigApplicationContext(TestImportBootstrap.class);
  9. System.out.println("context id : " + applicationContext.getId());
  10. TestSelector bean = applicationContext.getBean(TestSelector.class);
  11. System.out.println("TestSelector bean : " + bean);
  12. String[] beanNames = applicationContext.getBeanNamesForType(TestSelector.class);
  13. System.out.println("bean names:" + Arrays.asList(beanNames));
  14. applicationContext.close();
  15. }
  16. }
  17. 复制代码

spring容器启动后,控制台打印的结果:

context id : org.springframework.context.annotation.AnnotationConfigApplicationContext@238e0d81 TestSelector bean : TestSelector(id=@Import:ImportSelector) bean names:[com.spring.study.ioc.register.TestSelector]

由结果可以看出,TestSelector被注册到了spring容器中。与前面的直接注册相比,并没有看出ImportSelector接口的突出特性。本文只是简单的说明ImportSelector接口具有注册组件的功能,对于spring容器在启动时,如何执行BeanDefinitionRegistryPostProcessor来调用selectImports方法;如何使用ImportSelector接口实现更复杂的注册功能,将在后续文章中深入理解。

@Import 通过ImportBeanDefinitionRegistrar 注册

ImportBeanDefinitionRegistrar接口中只定义了一个registerBeanDefinitions方法,在此方法中,可以获取到BeanDefinitionRegistry对象,利用此对象,即可手动将需要的组件注册的spring容器中。在使用BeanDefinitionRegistry对象时,还可以指定组件在spring容器中注册的bean名称。


  
  1. /**
  2. * 通过 ImportBeanDefinitionRegistrar 接口手动注册组件
  3. */
  4. @Data
  5. public class TestRegistrar {
  6. private String id = "@Import:TestRegistrar";
  7. }
  8. 复制代码

自定义实现ImportBeanDefinitionRegistrar接口


  
  1. /**
  2. * 手动注册组件到IOC容器中
  3. */
  4. public class CustomImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar {
  5. /**
  6. * @param importingClassMetadata 标注了@Import配置类上面所有的注解信息
  7. * @param registry BeanDefinition注册器,可以通过此registry手动的向容器中注册指定的组件
  8. */
  9. public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
  10. if (!registry.containsBeanDefinition("testRegistrar")) {
  11. BeanDefinition definition = new RootBeanDefinition(TestRegistrar.class);
  12. registry.registerBeanDefinition("testRegistrar", definition);
  13. }
  14. }
  15. }
  16. 复制代码

@Import注解中指定ImportBeanDefinitionRegistrar实现类


  
  1. /**
  2. * spring 容器启动引导类
  3. */
  4. @Import(CustomImportBeanDefinitionRegistrar.class)
  5. public class TestImportBootstrap {
  6. public static void main(String[] args) {
  7. AnnotationConfigApplicationContext applicationContext =
  8. new AnnotationConfigApplicationContext(TestImportBootstrap.class);
  9. System.out.println("context id : " + applicationContext.getId());
  10. TestRegistrar bean = applicationContext.getBean(TestRegistrar.class);
  11. System.out.println("TestRegistrar bean : " + bean);
  12. String[] beanNames = applicationContext.getBeanNamesForType(TestSelector.class);
  13. System.out.println("bean names:" + Arrays.asList(beanNames));
  14. applicationContext.close();
  15. }
  16. }
  17. 复制代码

spring容器启动后,控制台打印的结果:

context id : org.springframework.context.annotation.AnnotationConfigApplicationContext@238e0d81 TestRegistrar bean : TestRegistrar(id=@Import:TestRegistrar) bean names:[testRegistrar]

由此可以看出,TestRegistrar被注册到了spring容器中。与ImportSelector接口一样,在spring容器启动时,通过BeanDefinitionRegistryPostProcessor来执行接口方法。

@Import同时指定多种接口注册

上面的例子中分别说明了使用@Import,通过直接导入Bean class,配置类,ImportSelector接口,ImportBeanDefinitionRegistrar接口来向spring容器中注册组件。当然在使用@Import注解时,可以同时指定上面的任意几种方式进行注册


  
  1. /**
  2. * spring 容器启动引导类
  3. *
  4. * @author TangFD
  5. * @since 2019/6/25.
  6. */
  7. @Import({
  8. TestComponent.class,
  9. TestConfiguration.class,
  10. CustomImportSelector.class,
  11. CustomImportBeanDefinitionRegistrar.class
  12. })
  13. public class TestImportBootstrap {
  14. public static void main(String[] args) {
  15. AnnotationConfigApplicationContext applicationContext =
  16. new AnnotationConfigApplicationContext(TestImportBootstrap.class);
  17. System.out.println("context id : " + applicationContext.getId());
  18. String[] beanNames = applicationContext.getBeanDefinitionNames();
  19. System.out.println("bean names:" + Arrays.asList(beanNames));
  20. applicationContext.close();
  21. }
  22. }
  23. 复制代码

spring容器启动后,控制台打印的结果:

context id : org.springframework.context.annotation.AnnotationConfigApplicationContext@238e0d81 bean names:[org.springframework.context.annotation.internalConfigurationAnnotationProcessor, org.springframework.context.annotation.internalAutowiredAnnotationProcessor, org.springframework.context.annotation.internalCommonAnnotationProcessor, org.springframework.context.event.internalEventListenerProcessor, org.springframework.context.event.internalEventListenerFactory, testImportBootstrap, com.spring.study.ioc.register.TestComponent, com.spring.study.ioc.register.TestConfiguration, testImport, testImport2, com.spring.study.ioc.register.TestSelector, testRegistrar]

总结

向spring容器中注册组件的方式有很多,本文主要说明了如何使用@Import注解向spring容器中注册组件。并且遗留了一个需要深入理解的知识点:在spring容器启动时,如何通过执行BeanDefinitionRegistryPostProcessor来执行ImportSelectorImportBeanDefinitionRegistrar接口方法进行组件注册。此处内容,将在后续的spring容器启动过程中,分析BeanFactoryPostProcessor接口执行过程里进行补充。

文章来源: baocl.blog.csdn.net,作者:小黄鸡1992,版权归原作者所有,如需转载,请联系作者。

原文链接:baocl.blog.csdn.net/article/details/94874137

【版权声明】本文为华为云社区用户转载文章,如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。