寫在前面java
向spring中註冊組件或者叫javaBean是使用spring的功能的前提條件。並且spring也提供了不少種方式,讓咱們能夠將普通的javaBean註冊到spring容器中,好比前一篇文章Spring Framework 組件註冊 之 @Component中寫的利用
@Component
註解將普通的javaBean註冊到容器中,本文說的@Import
註解也是spring Framework提供的將普通javaBean註冊到容器中,以及後續文章會說的@Configuration
,FactoryBean
等方式。spring
使用@Import
註冊一個普通Bean,只須要在@Import
註解中指定待註冊Bean的class便可數組
/** * 使用Import註解,註冊一個普通的Bean */
@Data
public class TestImport {
private String id = "@Import";
}
複製代碼
在spring啓動引導類中,添加@Import
註解app
/** * spring 容器啓動引導類 */
@Import(TestImport.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.getBeanNamesForType(TestImport.class);
System.out.println("Bean Name is : " + Arrays.toString(beanNames));
TestImport bean = applicationContext.getBean(TestImport.class);
System.out.println("TestImport bean : " + bean);
applicationContext.close();
}
}
複製代碼
spring容器啓動後,控制檯打印的結果:post
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的全類名spa
使用@Import
註解導入配置類,就會將配置類中的全部組件註冊到spring容器中。在spring中,並非@Configuration
標註的類纔是配置類,可是被@Configuration
標註的類會被生成代理對象,spring注入時與不使用@Configuration
註解有很大區別,後續會單獨說明此處內容,本文不在贅述。代理
/** * spring組件配置類 */
//@Configuration 使用@Import導入時,此註解能夠不加
public class TestConfiguration {
@Bean
public TestImport testImport() {
return new TestImport();
}
@Bean
public TestImport testImport2() {
return new TestImport();
}
}
複製代碼
@Import
註解中指定待導入的配置類code
/** * spring 容器啓動引導類 */
@Import(TestConfiguration.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.getBeanNamesForType(TestImport.class);
System.out.println("Bean Name is : " + Arrays.toString(beanNames));
TestImport bean = (TestImport) applicationContext.getBean("testImport");
System.out.println("TestImport bean : " + bean);
applicationContext.close();
}
}
複製代碼
spring容器啓動後,配置類中的註解一樣會被註冊到spring容器中:對象
context id : org.springframework.context.annotation.AnnotationConfigApplicationContext@21b8d17c Bean Name is : [testImport, testImport2] TestImport bean : TestImport(id=@Import)
由結果能夠看出,此時註冊的組件名稱即爲配置類中指定的組件名稱,而且經過配置類,能夠一次導入多個組件。
在ImportSelector
接口中只定義了一個接口selectImports
,經過此接口返回須要註冊的JavaBean的全類名數組,在使用@Import
導入時,會將接口返回的全部類註冊到spring容器中
/** * 經過 ImportSelector 接口註冊組件 */
@Data
public class TestSelector {
private String id = "@Import:ImportSelector";
}
複製代碼
自定義實現ImportSelector
接口
/** * 自定義組件選擇器,經過返回須要註冊的bean的全類名,進行快速的在IOC容器中註冊組件 */
public class CustomImportSelector implements ImportSelector {
/** * @param importingClassMetadata 標註了@Import配置類上面全部的註解信息 */
public String[] selectImports(AnnotationMetadata importingClassMetadata) {
return new String[]{TestSelector.class.getName()};
}
}
複製代碼
@Import
註解中指定ImportSelector實現類
/** * spring 容器啓動引導類 */
@Import(CustomImportSelector.class)
public class TestImportBootstrap {
public static void main(String[] args) {
AnnotationConfigApplicationContext applicationContext =
new AnnotationConfigApplicationContext(TestImportBootstrap.class);
System.out.println("context id : " + applicationContext.getId());
TestSelector bean = applicationContext.getBean(TestSelector.class);
System.out.println("TestSelector 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 TestSelector bean : TestSelector(id=@Import:ImportSelector) bean names:[com.spring.study.ioc.register.TestSelector]
由結果能夠看出,TestSelector
被註冊到了spring容器中。與前面的直接註冊相比,並無看出ImportSelector
接口的突出特性。本文只是簡單的說明ImportSelector
接口具備註冊組件的功能,對於spring容器在啓動時,如何執行BeanDefinitionRegistryPostProcessor
來調用selectImports
方法;如何使用ImportSelector
接口實現更復雜的註冊功能,將在後續文章中深刻理解。
在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
,經過直接導入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
接口執行過程裏進行補充。
學習永遠都不是一件簡單的事情,能夠有迷茫,能夠懶惰,可是前進的腳步永遠都不能中止。
不積跬步,無以致千里;不積小流,無以成江海;