當前位置:
首頁 >
前端技术
> javascript
>内容正文
javascript
【Spring注解系列05】@Import注入原理
生活随笔
收集整理的這篇文章主要介紹了
【Spring注解系列05】@Import注入原理
小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.
1.@Import注解
- 用于注入指定的類,導(dǎo)入組件id默認是組件的全類名。
- 只能作用于類上。
- 屬性:value = {xx.class,xx.class}? ? ? ? 說明:xx.class為要導(dǎo)入到容器中的組件
屬性value中class分為三類:
? ? ?1)普通類直接注入
? ? ?2)實現(xiàn)ImportSelector接口的類
? ? ?3)實現(xiàn)ImportBeanDefinitionRegistrar接口的類
說明:
- ImportSelector:返回需要導(dǎo)入的組件的全類名數(shù)組;
- ImportBeanDefinitionRegistrar:手動注冊bean到容器中;
?
2.@Import注入原理
import類注入是通過org.springframework.context.annotation.ConfigurationClassPostProcessor后置處理器來注入的。
核心方法:postProcessBeanDefinitionRegistry
/*** Derive further bean definitions from the configuration classes in the registry.*/@Overridepublic void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) {int registryId = System.identityHashCode(registry);//判斷后置處理器在registriesPostProcessed和factoriesPostProcessed中有沒有被調(diào)用過if (this.registriesPostProcessed.contains(registryId)) {throw new IllegalStateException("postProcessBeanDefinitionRegistry already called on this post-processor against " + registry);}if (this.factoriesPostProcessed.contains(registryId)) {throw new IllegalStateException("postProcessBeanFactory already called on this post-processor against " + registry);}//調(diào)用前保存registryId,防止被重復(fù)調(diào)用this.registriesPostProcessed.add(registryId);//注入標有@configuration的對象processConfigBeanDefinitions(registry);}/** 構(gòu)建和校驗標有@configuration注解的對象* Build and validate a configuration model based on the registry of* {@link Configuration} classes. */public void processConfigBeanDefinitions(BeanDefinitionRegistry registry) {//configCandidates 需要注入的所有標注@configuration的類List<BeanDefinitionHolder> configCandidates = new ArrayList<>();String[] candidateNames = registry.getBeanDefinitionNames();…………// Return immediately if no @Configuration classes were foundif (configCandidates.isEmpty()) {return;}…………// Parse each @Configuration classConfigurationClassParser parser = new ConfigurationClassParser(this.metadataReaderFactory, this.problemReporter, this.environment,this.resourceLoader, this.componentScanBeanNameGenerator, registry);Set<BeanDefinitionHolder> candidates = new LinkedHashSet<>(configCandidates);Set<ConfigurationClass> alreadyParsed = new HashSet<>(configCandidates.size());do {//核心方法 解析@configuration的類parser.parse(candidates);parser.validate();…………}while (!candidates.isEmpty());// Register the ImportRegistry as a bean in order to support ImportAware @Configuration classes…………}// 進行 parse解析,獲得configClass protected final void parse(AnnotationMetadata metadata, String beanName) throws IOException {processConfigurationClass(new ConfigurationClass(metadata, beanName));}protected void processConfigurationClass(ConfigurationClass configClass) throws IOException {…………//注入configuration class的上級類// Recursively process the configuration class and its superclass hierarchy.SourceClass sourceClass = asSourceClass(configClass);do {//核心方法,加載上級類,直到為nullsourceClass = doProcessConfigurationClass(configClass, sourceClass);}while (sourceClass != null);this.configurationClasses.put(configClass, configClass);}/*** Apply processing and build a complete {@link ConfigurationClass} by reading the* annotations, members and methods from the source class. This method can be called* multiple times as relevant sources are discovered.* @param configClass the configuration class being build* @param sourceClass a source class* @return the superclass, or {@code null} if none found or previously processed*/@Nullableprotected final SourceClass doProcessConfigurationClass(ConfigurationClass configClass, SourceClass sourceClass)throws IOException {//加載@Component組件if (configClass.getMetadata().isAnnotated(Component.class.getName())) {// Recursively process any member (nested) classes firstprocessMemberClasses(configClass, sourceClass);}//加載@PropertySource組件// Process any @PropertySource annotationsfor (AnnotationAttributes propertySource : AnnotationConfigUtils.attributesForRepeatable(sourceClass.getMetadata(), PropertySources.class,org.springframework.context.annotation.PropertySource.class)) {…………}//加載@ComponentScan 組件// Process any @ComponentScan annotationsSet<AnnotationAttributes> componentScans = AnnotationConfigUtils.attributesForRepeatable(sourceClass.getMetadata(), ComponentScans.class, ComponentScan.class);if (!componentScans.isEmpty() &&!this.conditionEvaluator.shouldSkip(sourceClass.getMetadata(), ConfigurationPhase.REGISTER_BEAN)) {for (AnnotationAttributes componentScan : componentScans) {// The config class is annotated with @ComponentScan -> perform the scan immediately…………}}}//加載@Import 組件 這就是Import導(dǎo)入的組件// Process any @Import annotationsprocessImports(configClass, sourceClass, getImports(sourceClass), true);//@ImportResource 組件// Process any @ImportResource annotationsAnnotationAttributes importResource =AnnotationConfigUtils.attributesFor(sourceClass.getMetadata(), ImportResource.class);…………}//@Bean組件// Process individual @Bean methodsSet<MethodMetadata> beanMethods = retrieveBeanMethodMetadata(sourceClass);for (MethodMetadata methodMetadata : beanMethods) {configClass.addBeanMethod(new BeanMethod(methodMetadata, configClass));}// Process default methods on interfacesprocessInterfaces(configClass, sourceClass);// Process superclass, if anyif (sourceClass.getMetadata().hasSuperClass()) {String superclass = sourceClass.getMetadata().getSuperClassName();if (superclass != null && !superclass.startsWith("java") &&!this.knownSuperclasses.containsKey(superclass)) {this.knownSuperclasses.put(superclass, configClass);// Superclass found, return its annotation metadata and recursereturn sourceClass.getSuperClass();}}// No superclass -> processing is completereturn null;}?
3.實例
實體類:
public class ImportBean {}public class ImportBean2 {}public class ImportBean3 {}public class ImportBean4 {}實現(xiàn)ImportSelector和ImportBeanDefinitionRegistrar接口類
//自定義邏輯返回需要導(dǎo)入的組件 public class BeanImportSelector implements ImportSelector {//返回值,就是到導(dǎo)入到容器中的組件全類名//AnnotationMetadata:當前標注@Import注解的類的所有注解信息@Overridepublic String[] selectImports(AnnotationMetadata importingClassMetadata) {//importingClassMetadata//方法不要返回null值System.out.println(importingClassMetadata);return new String[]{"com.java.model.ImportBean2","com.java.model.ImportBean3"};} }public class MyImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar {/*** AnnotationMetadata:當前類的注解信息* BeanDefinitionRegistry:BeanDefinition注冊類;* 把所有需要添加到容器中的bean;調(diào)用* BeanDefinitionRegistry.registerBeanDefinition手工注冊進來*/@Overridepublic void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {//指定Bean定義信息;(Bean的類型,Bean。。。)RootBeanDefinition beanDefinition = new RootBeanDefinition(ImportBean4.class);//注冊一個Bean,指定bean名registry.registerBeanDefinition("registrar_ImportBean4", beanDefinition);} }配置類:
@Configuration @Import({ImportBean.class, BeanImportSelector.class, MyImportBeanDefinitionRegistrar.class}) public class BeanImportConfig {}測試類:
public class BeanImportTest {public static void main(String[] args) {ApplicationContext applicationContext = new AnnotationConfigApplicationContext(BeanImportConfig.class);String[] beanDefinitionNames = applicationContext.getBeanDefinitionNames();for (String name : beanDefinitionNames) {System.out.println(name);}} }運行結(jié)果: org.springframework.core.type.StandardAnnotationMetadata@1a0dcaa 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 beanImportConfig com.java.model.ImportBean //普通類直接注入 com.java.model.ImportBean2 //通過ImportSelector接口注入 com.java.model.ImportBean3 //通過ImportSelector接口注入 registrar_ImportBean4 //通過ImportBeanDefinitionRegistrar注入?
?
《新程序員》:云原生和全面數(shù)字化實踐50位技術(shù)專家共同創(chuàng)作,文字、視頻、音頻交互閱讀總結(jié)
以上是生活随笔為你收集整理的【Spring注解系列05】@Import注入原理的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 【深入Java虚拟机JVM 05】Hot
- 下一篇: 【Spring注解系列06】Factor