簡介
Spring的工具類ConfigurationClassParser用於分析@Configuration註解的配置類,產生一組ConfigurationClass對象。它的分析過程會接受一組種子配置類(調用者已知的配置類,通常很可能只有一個),從這些種子配置類開始分析所有關聯的配置類,分析過程主要是遞歸分析配置類的註解@Import,配置類內部嵌套類,找出其中所有的配置類,然後返回這組配置類。
該工具主要由ConfigurationClassPostProcessor使用,而ConfigurationClassPostProcessor是一個BeanDefinitionRegistryPostProcessor/BeanFactoryPostProcessor,它會在容器啓動過程中,應用上下文上執行各個BeanFactoryPostProcessor時被執行。
ConfigurationClassParser 所在包 : org.springframework.context.annotation。
這個工具類自身的邏輯並不註冊bean定義,它的主要任務是發現@Configuration註解的所有配置類並將這些配置類交給調用者(調用者會通過其他方式註冊其中的bean定義),而對於非@Configuration註解的其他bean定義,比如@Component註解的bean定義,該工具類使用另外一個工具ComponentScanAnnotationParser掃描和註冊它們。
該工具類對@ComponentScans,@ComponentScan註解的處理使用了ComponentScanAnnotationParser,ComponentScanAnnotationParser在掃描到bean定義時會直接將其註冊到容器,而不是採用和ConfigurationClassParser類似的方式交由調用者處理。
一般情況下一個@Configuration註解的類只會產生一個ConfigurationClass對象,但是因爲@Configuration註解的類可能會使用註解@Import引入其他配置類,也可能內部嵌套定義配置類,所以總的來看,ConfigurationClassParser分析一個@Configuration註解的類,可能產生任意多個ConfigurationClass對象。
主要功能分析
以下源代碼基於 Spring 4.3.12.RELEASE
parse() : 外部調用入口
parse()方法的主體工作流程 :
接收外部提供的參數 configCandidates , 是一組需要被分析的候選配置類的集合,每個元素使用類型BeanDefinitionHolder包裝 ;
parse() 方法針對每個候選配置類元素BeanDefinitionHolder,執行以下邏輯 :
1.將其封裝成一個ConfigurationClass
2.調用processConfigurationClass(ConfigurationClass configClass)
> 分析過的每個配置類都被保存到屬性 this.configurationClasses 中。
/** * @參數 configCandidates : 外部指定需要被分析的一組候選配置類 **/ public void parse(Set<BeanDefinitionHolder> configCandidates) { this.deferredImportSelectors = new LinkedList<DeferredImportSelectorHolder>(); for (BeanDefinitionHolder holder : configCandidates) { BeanDefinition bd = holder.getBeanDefinition(); try { // 這裏根據Bean定義的不同類型走不同的分支,但是最終都會調用到方法 // processConfigurationClass(ConfigurationClass configClass) if (bd instanceof AnnotatedBeanDefinition) { // bd 是一個 AnnotatedBeanDefinition parse(((AnnotatedBeanDefinition) bd).getMetadata(), holder.getBeanName()); } else if (bd instanceof AbstractBeanDefinition && ((AbstractBeanDefinition) bd).hasBeanClass()) { // bd 是一個 AbstractBeanDefinition,並且指定 beanClass 屬性 parse(((AbstractBeanDefinition) bd).getBeanClass(), holder.getBeanName()); } else { // 其他情況 parse(bd.getBeanClassName(), holder.getBeanName()); } } catch (BeanDefinitionStoreException ex) { throw ex; } catch (Throwable ex) { throw new BeanDefinitionStoreException( "Failed to parse configuration class [" + bd.getBeanClassName() + "]", ex); } } // 執行找到的 DeferredImportSelector // DeferredImportSelector 是 ImportSelector 的一個變種。 // ImportSelector 被設計成其實和@Import註解的類同樣的導入效果,但是實現 ImportSelector // 的類可以條件性地決定導入哪些配置。 // DeferredImportSelector 的設計目的是在所有其他的配置類被處理後才處理。這也正是 // 該語句被放到本函數最後一行的原因。 processDeferredImportSelectors(); }
processConfigurationClass() 分析一個配置類
processConfigurationClass()對配置的處理並不是真正自己處理,而是開始一個基於doProcessConfigurationClass()的處理循環,該循環從參數配置類開始遍歷其所有需要處理的父類(super),每個類都使用doProcessConfigurationClass()來處理。每處理一個類,processConfigurationClass()將其記錄到this.configurationClasses。
/** * 用於分析一個 ConfigurationClass,分析之後將它記錄到已處理配置類記錄 **/ protected void processConfigurationClass(ConfigurationClass configClass) throws IOException { if (this.conditionEvaluator.shouldSkip(configClass.getMetadata(), ConfigurationPhase.PARSE_CONFIGURATION)) { return; } ConfigurationClass existingClass = this.configurationClasses.get(configClass); if (existingClass != null) { if (configClass.isImported()) { if (existingClass.isImported()) { //如果要處理的配置類configClass在已經分析處理的配置類記錄中已存在, //合併二者的importedBy屬性 existingClass.mergeImportedBy(configClass); } // Otherwise ignore new imported config class; existing non-imported class overrides it. return; } else { // Explicit bean definition found, probably replacing an import. // Let's remove the old one and go with the new one. this.configurationClasses.remove(configClass); for (Iterator<ConfigurationClass> it = this.knownSuperclasses.values().iterator(); it.hasNext();) { if (configClass.equals(it.next())) { it.remove(); } } } } // Recursively process the configuration class and its superclass hierarchy. // 從當前配置類configClass開始向上沿着類繼承結構逐層執行doProcessConfigurationClass, // 直到遇到的父類是由Java提供的類結束循環 SourceClass sourceClass = asSourceClass(configClass); do { // 循環處理配置類configClass直到sourceClass變爲null // doProcessConfigurationClass的返回值是其參數configClass的父類, // 如果該父類是由Java提供的類或者已經處理過,返回null sourceClass = doProcessConfigurationClass(configClass, sourceClass); } while (sourceClass != null); // 需要被處理的配置類configClass已經被分析處理,將它記錄到已處理配置類記錄 this.configurationClasses.put(configClass, configClass); }
processDeferredImportSelectors() 處理需要延遲處理的ImportSelector
/** * 對屬性deferredImportSelectors中記錄的DeferredImportSelector進行處理 **/ private void processDeferredImportSelectors() { List<DeferredImportSelectorHolder> deferredImports = this.deferredImportSelectors; this.deferredImportSelectors = null; Collections.sort(deferredImports, DEFERRED_IMPORT_COMPARATOR); // 循環處理每個DeferredImportSelector for (DeferredImportSelectorHolder deferredImport : deferredImports) { ConfigurationClass configClass = deferredImport.getConfigurationClass(); try { //調用DeferredImportSelector的方法selectImports,獲取需要被導入的類的名稱 String[] imports = deferredImport.getImportSelector().selectImports(configClass.getMetadata()); // 處理任何一個 @Import 註解 processImports(configClass, asSourceClass(configClass), asSourceClasses(imports), false); } catch (BeanDefinitionStoreException ex) { throw ex; } catch (Throwable ex) { throw new BeanDefinitionStoreException( "Failed to process import candidates for configuration class [" + configClass.getMetadata().getClassName() + "]", ex); } } }
doProcessConfigurationClass()對一個配置類執行真正的處理
doProcessConfigurationClass()會對一個配置類執行真正的處理:
- 一個配置類的成員類(配置類內嵌套定義的類)也可能適配類,先遍歷這些成員配置類,調用processConfigurationClass處理它們;
- 處理配置類上的註解@PropertySources,@PropertySource
- 處理配置類上的註解@ComponentScans,@ComponentScan
- 處理配置類上的註解@Import
- 處理配置類上的註解@ImportResource
- 處理配置類中每個帶有@Bean註解的方法
- 處理配置類所實現接口的缺省方法
- 檢查父類是否需要處理,如果父類需要處理返回父類,否則返回null
返回父類表示當前配置類處理尚未完成,調用者processConfigurationClass會繼續處理其父類;返回null才表示該配置類的處理完成。從這裏可以推斷一旦一個配置類被processConfigurationClass處理完成,表示其自身,內部嵌套類,各個實現接口以及各級父類都被處理完成。
/** * Apply processing and build a complete 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 null if none found or previously processed */ protected final SourceClass doProcessConfigurationClass(ConfigurationClass configClass, SourceClass sourceClass) throws IOException { // Recursively process any member (nested) classes first,首先遞歸處理嵌套類 processMemberClasses(configClass, sourceClass); // Process any @PropertySource annotations,處理每個@PropertySource註解 for (AnnotationAttributes propertySource : AnnotationConfigUtils.attributesForRepeatable( sourceClass.getMetadata(), PropertySources.class, org.springframework.context.annotation.PropertySource.class)) { if (this.environment instanceof ConfigurableEnvironment) { processPropertySource(propertySource); } else { logger.warn("Ignoring @PropertySource annotation on [" + sourceClass.getMetadata().getClassName() + "]. Reason: Environment must implement ConfigurableEnvironment"); } } // Process any @ComponentScan annotations,處理每個@ComponentScan註解 Set<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) { // 該配置類上註解了@ComponentScan,現在執行掃描,獲取其中的Bean定義 // this.componentScanParser 是一個 ComponentScanAnnotationParser,在當前對象的構造函數中 // 被創建 Set<BeanDefinitionHolder> scannedBeanDefinitions = this.componentScanParser.parse(componentScan, sourceClass.getMetadata().getClassName()); // 對Component scan得到的Bean定義做檢查,看看裏面是否有需要處理的配置類, // 有的話對其做分析處理 for (BeanDefinitionHolder holder : scannedBeanDefinitions) { if (ConfigurationClassUtils.checkConfigurationClassCandidate( holder.getBeanDefinition(), this.metadataReaderFactory)) { // 如果該Bean定義是一個配置類,它進行分析 parse(holder.getBeanDefinition().getBeanClassName(), holder.getBeanName()); } } } } // Process any @Import annotations,處理每個@Import註解 // 注意這裏調用到了getImports()方法,它會蒐集sourceClass上所有的@Import註解的value值, // 具體蒐集的方式是訪問sourceClass直接註解的@Import以及遞歸訪問它的註解中隱含的所有的@Import processImports(configClass, sourceClass, getImports(sourceClass), true); // Process any @ImportResource annotations,處理每個@ImportResource註解 if (sourceClass.getMetadata().isAnnotated(ImportResource.class.getName())) { AnnotationAttributes importResource = AnnotationConfigUtils.attributesFor(sourceClass.getMetadata(), ImportResource.class); String[] resources = importResource.getStringArray("locations"); Class<? extends BeanDefinitionReader> readerClass = importResource.getClass("reader"); for (String resource : resources) { String resolvedResource = this.environment.resolveRequiredPlaceholders(resource); configClass.addImportedResource(resolvedResource, readerClass); } } // Process individual @Bean methods,處理配置類中每個帶有@Bean註解的方法 Set<MethodMetadata> beanMethods = retrieveBeanMethodMetadata(sourceClass); for (MethodMetadata methodMetadata : beanMethods) { configClass.addBeanMethod(new BeanMethod(methodMetadata, configClass)); } // Process default methods on interfaces,處理接口上的缺省方法 processInterfaces(configClass, sourceClass); // Process superclass, if any // 如果父類superclass存在,並且不是`java`包中的類,並且尚未處理處理, // 則才返回它以便外層循環繼續 if (sourceClass.getMetadata().hasSuperClass()) { String superclass = sourceClass.getMetadata().getSuperClassName(); if (!superclass.startsWith("java") && !this.knownSuperclasses.containsKey(superclass)) { this.knownSuperclasses.put(superclass, configClass); // Superclass found, return its annotation metadata and recurse return sourceClass.getSuperClass(); } } // No superclass -> processing is complete,沒找到需要處理的父類,處理結果 return null;// 用返回null告訴外層循環結束 }
processImports()處理配置類上蒐集到的@Import註解
/** * 處理配置類上蒐集到的@Import註解 * 參數 configuClass 配置類 * 參數 currentSourceClass 當前源碼類 * 參數 importCandidates, 所有的@Import註解的value * 參數 checkForCircularImports, 是否檢查循環導入 **/ private void processImports(ConfigurationClass configClass, SourceClass currentSourceClass, Collection<SourceClass> importCandidates, boolean checkForCircularImports) throws IOException { if (importCandidates.isEmpty()) { // 如果配置類上沒有任何候選@Import,說明沒有需要處理的導入,則什麼都不用做,直接返回 return; } if (checkForCircularImports && isChainedImportOnStack(configClass)) { // 如果要求做循環導入檢查,並且檢查到了循環依賴,報告這個問題 this.problemReporter.error(new CircularImportProblem(configClass, this.importStack)); } else { // 開始處理配置類configClass上所有的@Import importCandidates this.importStack.push(configClass); try { // 循環處理每一個@Import,每個@Import可能導入三種類型的類 : // 1. ImportSelector // 2. ImportBeanDefinitionRegistrar // 3. 其他類型,都當作配置類處理,也就是相當於使用了註解@Configuration的配置類 // 下面的for循環中對這三種情況執行了不同的處理邏輯 for (SourceClass candidate : importCandidates) { if (candidate.isAssignable(ImportSelector.class)) { // Candidate class is an ImportSelector -> delegate to it to determine imports Class<?> candidateClass = candidate.loadClass(); ImportSelector selector = BeanUtils.instantiateClass(candidateClass, ImportSelector.class); ParserStrategyUtils.invokeAwareMethods( selector, this.environment, this.resourceLoader, this.registry); if (this.deferredImportSelectors != null && selector instanceof DeferredImportSelector) { this.deferredImportSelectors.add( new DeferredImportSelectorHolder(configClass, (DeferredImportSelector) selector)); } else { String[] importClassNames = selector.selectImports(currentSourceClass.getMetadata()); Collection<SourceClass> importSourceClasses = asSourceClasses(importClassNames); processImports(configClass, currentSourceClass, importSourceClasses, false); } } else if (candidate.isAssignable(ImportBeanDefinitionRegistrar.class)) { // Candidate class is an ImportBeanDefinitionRegistrar -> // delegate to it to register additional bean definitions Class<?> candidateClass = candidate.loadClass(); ImportBeanDefinitionRegistrar registrar = BeanUtils.instantiateClass(candidateClass, ImportBeanDefinitionRegistrar.class); ParserStrategyUtils.invokeAwareMethods( registrar, this.environment, this.resourceLoader, this.registry); configClass.addImportBeanDefinitionRegistrar(registrar, currentSourceClass.getMetadata()); } else { // Candidate class not an ImportSelector or ImportBeanDefinitionRegistrar -> // process it as an @Configuration class this.importStack.registerImport( currentSourceClass.getMetadata(), candidate.getMetadata().getClassName()); processConfigurationClass(candidate.asConfigClass(configClass)); } } } catch (BeanDefinitionStoreException ex) { throw ex; } catch (Throwable ex) { throw new BeanDefinitionStoreException( "Failed to process import candidates for configuration class [" + configClass.getMetadata().getClassName() + "]", ex); } finally { this.importStack.pop(); } } }
版權聲明:本文爲CSDN博主「安迪源文」的原創文章,遵循CC 4.0 BY-SA版權協議,轉載請附上原文出處鏈接及本聲明。
原文鏈接:https://blog.csdn.net/andy_zhang2007/article/details/78549773