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名称。
/** * 通过 ImportBeanDefinitionRegistrar 接口手动注册组件 */ @Data public class TestRegistrar { private String id = "@Import:TestRegistrar"; }自定义实现ImportBeanDefinitionRegistrar接口
/** * 手动注册组件到IOC容器中 */ public class CustomImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar { /** * @param importingClassMetadata 标注了@Import配置类上面所有的注解信息 * @param registry BeanDefinition注册器,可以通过此registry手动的向容器中注册指定的组件 */ public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) { if (!registry.containsBeanDefinition("testRegistrar")) { BeanDefinition definition = new RootBeanDefinition(TestRegistrar.class); registry.registerBeanDefinition("testRegistrar", definition); } } }@Import注解中指定ImportBeanDefinitionRegistrar实现类
/** * spring 容器启动引导类 */ @Import(CustomImportBeanDefinitionRegistrar.class) public class TestImportBootstrap { public static void main(String[] args) { AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(TestImportBootstrap.class); System.out.println("context id : " + applicationContext.getId()); TestRegistrar bean = applicationContext.getBean(TestRegistrar.class); System.out.println("TestRegistrar bean : " + bean); String[] beanNames = applicationContext.getBeanNamesForType(TestSelector.class); System.out.println("bean names:" + Arrays.asList(beanNames)); applicationContext.close(); } }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注解时,可以同时指定上面的任意几种方式进行注册
/** * spring 容器启动引导类 * * @author TangFD * @since 2019/6/25. */ @Import({ TestComponent.class, TestConfiguration.class, CustomImportSelector.class, CustomImportBeanDefinitionRegistrar.class }) public class TestImportBootstrap { public static void main(String[] args) { AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(TestImportBootstrap.class); System.out.println("context id : " + applicationContext.getId()); String[] beanNames = applicationContext.getBeanDefinitionNames(); System.out.println("bean names:" + Arrays.asList(beanNames)); applicationContext.close(); } }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来执行ImportSelector和ImportBeanDefinitionRegistrar接口方法进行组件注册。此处内容,将在后续的spring容器启动过程中,分析BeanFactoryPostProcessor接口执行过程里进行补充。
学习永远都不是一件简单的事情,可以有迷茫,可以懒惰,但是前进的脚步永远都不能停止。
不积跬步,无以至千里;不积小流,无以成江海;