(轉)Spring 工具類 ConfigurationClassParser 分析得到配置類 -- springboot一樣處理過程

簡介

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()會對一個配置類執行真正的處理:

  1. 一個配置類的成員類(配置類內嵌套定義的類)也可能適配類,先遍歷這些成員配置類,調用processConfigurationClass處理它們;
  2. 處理配置類上的註解@PropertySources,@PropertySource
  3. 處理配置類上的註解@ComponentScans,@ComponentScan
  4. 處理配置類上的註解@Import
  5. 處理配置類上的註解@ImportResource
  6. 處理配置類中每個帶有@Bean註解的方法
  7. 處理配置類所實現接口的缺省方法
  8. 檢查父類是否需要處理,如果父類需要處理返回父類,否則返回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

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章