spring 5.0.x源碼學習系列六: 后置處理器ConfigurationClassPostProcessor之BeanDefinitionRegistryPostProcessor身份

前言

一、ConfigurationClassPostProcessor之BeanDefinitionRegistryPostProcessor身份

  • 它的這個身份起到了非常重要的作用: 處理配置類并解析它們。 這句話可能有點難理解, 我們根據下面的篇幅慢慢理解。

二、流程圖

  • 這里提供一張處理配置類流程圖, 結合項目demo一起看


    在這里插入圖片描述

三、項目demo

3.1 項目全景圖

在這里插入圖片描述

3.1.1 EnableProxy類

在這里插入圖片描述

3.1.2 ImportEugene類

在這里插入圖片描述

3.1.3 UserDaoImpl類

在這里插入圖片描述

3.1.4 ImportEugeneImportSelector類

在這里插入圖片描述

3.1.5 MyImportBeanDefinitionRegistrar類

在這里插入圖片描述

3.1.6 ImportEugeneBeanFactoryProcessor類

在這里插入圖片描述

3.1.7 JDKProxyPostProcessor類

在這里插入圖片描述

3.1.8 MyInvocationHandler類

在這里插入圖片描述

3.1.9 ProxyUtil類

在這里插入圖片描述

3.1.10 UserServiceImpl類

在這里插入圖片描述

3.1.11 UserService類

在這里插入圖片描述

3.1.12 AppConfig類

在這里插入圖片描述

3.1.13 Entry類

在這里插入圖片描述

3.1.14 TestBeanInAppConfig類

在這里插入圖片描述

3.1.15 TestDaoInUserDaoImpl類

在這里插入圖片描述

3.2 demo運行結果

  1. AppConfig存在@ImportEugene@EnableProxy注解時, 運行結果如下:

    在這里插入圖片描述

    => 打印了7句 ========ImportEugene========的原因是有7個bean要創建, 分別為如下7個bean:AppConfig, UserServiceImpl, UserDaoImpl, ImportEugeneBeanFactoryProcessor, JDKProxyPostProcessor, TestBeanInAppConfig, TestDaoInUserDaoImpl

  2. AppConfig去除@ImportEugene@EnableProxy注解時, 運行結果如下:

    在這里插入圖片描述

    在這里插入圖片描述

    在這里插入圖片描述

3.4 Demo運行結果總結

  • 本demo利用了spring的兩個大擴展點: BeanPostProcessor@Import注解。其中自定義注解 @EnableProxy@ImportEugene利用了 @Import注解擴展點的兩種類型: ImportSelectorImportBeanDefinitionRegistrar來實現

  • 關于上述的三個點BeanPostProcessor, ImportSelector, ImportSelector的功能將以如下表格來闡述

    擴展點 提供api 作用 使用示例
    BeanPostProcessor beanName和當前bean對象 可以動態修改bean 本案例中的為UserServiceImpl對象生成代理對象
    ImportSelector AnnotationMetadata 能獲取到被導入的那個類的信息, 可以根據自定義的注解來動態寫邏輯, 返回的字符串數組為類的全類名, spring會把他們當成bean去實例化 本案例中的ImportEugeneBeanFactoryProcessor, 動態的添加指定bean
    ImportBeanDefinitionRegistrar AnnotationMetadata和BeanDefinitionRegistry 擁有ImportSelector的api, 同時還能獲取到BeanDefinitionRegister 本案例中的MyImportBeanDefinitionRegistrar, 動態的添加beanDefinition

四、運行原理

4.1 前言

  • 本demo中的演示只有幾個部分和ConfigurationClassPostProcessor的BeanDefinitionRegistryPostProcessor身份有關, 只要涉及到bean的創建和bean的執行順序, 都不屬于本篇博客的內容, 添加一個demo演示是為了更好的說明問題, 現在開始總結原理

4.2 執行原理

4.2.1 在上篇博客中有總結到invokeBeanFactoryPostProcessors方法執行后置處理器的幾個順序。我們現在將從調用ConfigurationClassPostProcessor的postProcessBeanDefinitionRegistry方法開始

  1. postProcessBeanDefinitionRegistry方法源碼

    @Override
    public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) {
        int registryId = System.identityHashCode(registry);
        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);
        }
        this.registriesPostProcessed.add(registryId);
    
        // 開始處理配置類, registry為bean工廠
        processConfigBeanDefinitions(registry);
    }
    
  2. processConfigBeanDefinitions處理配置類

    public void processConfigBeanDefinitions(BeanDefinitionRegistry registry) {
        // 存儲配置類的數據結構: 很重要, 后續將解析此集合
        List<BeanDefinitionHolder> configCandidates = new ArrayList<>();
    
        // 獲取bean工廠的所有beanDefinition的名稱, 在本次demo中, 一共有7個beanDefinition
        // 為spring內置的6個beanDefinition + AppConfig beanDefinition
        String[] candidateNames = registry.getBeanDefinitionNames();
    
        // 遍歷beanDefinition
        for (String beanName : candidateNames) {
    
            // 根據beanName到bean工廠中拿到beanDefinition
            BeanDefinition beanDef = registry.getBeanDefinition(beanName);
    
            // 判斷是否為全注解或者部分注解  => 這里正常的spring流程下, 應該都沒標注
            // 除非程序員自己利用擴展點修改了配置類對應的標識
            // eg: 標識它為全配置類
            // 配置類對應的beanDefinition.setAttribute(
            // "org.springframework.context.annotation.
            // ConfigurationClassPostProcessor.configurationClass", "full");
            // eg: 標識它為部分配置類
            // 配置類對應的beanDefinition.setAttribute(
            // "org.springframework.context.annotation.
            // ConfigurationClassPostProcessor.configurationClass", "lite");
            if (ConfigurationClassUtils.isFullConfigurationClass(beanDef) ||
                    ConfigurationClassUtils.isLiteConfigurationClass(beanDef)) {
                if (logger.isDebugEnabled()) {
                    logger.debug("Bean definition has already been processed as a configuration class: " + beanDef);
                }
            }
            // 正常情況下會走else, 
            // ConfigurationClassUtils.checkConfigurationClassCandidate的核心邏輯應該為如下代碼
            // if (isFullConfigurationCandidate(metadata)) {
            //     beanDef.setAttribute(CONFIGURATION_CLASS_ATTRIBUTE, CONFIGURATION_CLASS_FULL);
            // }
            // else if (isLiteConfigurationCandidate(metadata)) {
            //     beanDef.setAttribute(CONFIGURATION_CLASS_ATTRIBUTE, CONFIGURATION_CLASS_LITE);
            // }
            // 若當前遍歷的beanDefinition是一個配置類或者全配置類則給他一個標識, 并返回true
            // 進而將當前的beanDefinition添加到configCandidates數據結構中
            // 這里總結下什么叫全配置類什么叫部分配置類
            // 全配置類: 加了@Configuration注解
            // 部分配置類: 類中有@Component、@Import、@ImportResource、@ComponentScan注解及方法中有@Bean注解的類
            else if (ConfigurationClassUtils.checkConfigurationClassCandidate(beanDef, this.metadataReaderFactory)) {
                configCandidates.add(new BeanDefinitionHolder(beanDef, beanName));
            }
        }
    
        // Return immediately if no @Configuration classes were found
        // 若bean工廠中無配置類, 那么將結束解析配置類的流程
        if (configCandidates.isEmpty()) {
            return;
        }
    
        // Sort by previously determined @Order value, if applicable
        configCandidates.sort((bd1, bd2) -> {
            int i1 = ConfigurationClassUtils.getOrder(bd1.getBeanDefinition());
            int i2 = ConfigurationClassUtils.getOrder(bd2.getBeanDefinition());
            return Integer.compare(i1, i2);
        });
    
        // Detect any custom bean name generation strategy supplied through the enclosing application context
        // 還未總結到它的具體作用
        SingletonBeanRegistry sbr = null;
        if (registry instanceof SingletonBeanRegistry) {
            sbr = (SingletonBeanRegistry) registry;
            if (!this.localBeanNameGeneratorSet) {
                BeanNameGenerator generator = (BeanNameGenerator) sbr.getSingleton(CONFIGURATION_BEAN_NAME_GENERATOR);
                if (generator != null) {
                    this.componentScanBeanNameGenerator = generator;
                    this.importBeanNameGenerator = generator;
                }
            }
        }
    
        if (this.environment == null) {
            this.environment = new StandardEnvironment();
        }
    
        // Parse each @Configuration class
        // 生成一個配置類的解析器, 將使用它來對配置類進行解析
        ConfigurationClassParser parser = new ConfigurationClassParser(
                this.metadataReaderFactory, this.problemReporter, this.environment,
                this.resourceLoader, this.componentScanBeanNameGenerator, registry);
    
        // 存放在解析配置類過程中得到的新的配置類, eg: 在解析@ComponentScan注解的掃描路徑時,
        // 有可能掃描到其他的配置類
        Set<BeanDefinitionHolder> candidates = new LinkedHashSet<>(configCandidates);
    
        // 將register方法中或者使用spring擴展點手動添加到bean工廠的配置類添加到存放解析完畢的數據結構中,
        // 為什么這么做? 因為后續將挨個去解析candidates的配置類, 并將新掃描出來或者import進去的
        // 配置類也添加到candidates里面去了, 不需要再解析一遍
        Set<ConfigurationClass> alreadyParsed = new HashSet<>(configCandidates.size());
    
        do {
            // 解析配置類, 執行到此, candidates中只有一個元素,
            // 因為在執行這個步驟的時候只有AppConfig對應的beanDefinition在bean工廠中
            parser.parse(candidates);
            parser.validate();
    
            // 拿到配置類解析器得到的配置類
            Set<ConfigurationClass> configClasses = new LinkedHashSet<>(parser.getConfigurationClasses());
    
            // 移出已經解析的配置類
            configClasses.removeAll(alreadyParsed);
    
            // Read the model and create bean definitions based on its content
            if (this.reader == null) {
                this.reader = new ConfigurationClassBeanDefinitionReader(
                        registry, this.sourceExtractor, this.resourceLoader, this.environment,
                        this.importBeanNameGenerator, parser.getImportRegistry());
            }
    
            // 加載掃描出來的所有beanDefinition, 并在此將它們挨個注冊到spring bean工廠中
            // 所以執行到這里時, configClasses中存儲元素內容應該為:
            // 根據candidates中的配置類解析出來的所有配置類
            // (包括@Component注解的類、@Import注解導入的普通類、@Configuration的類)
            this.reader.loadBeanDefinitions(configClasses);
            alreadyParsed.addAll(configClasses);
    
            candidates.clear();
            // 這里還會校驗這樣一種情況,因為所有配置類是存到candidates變量中
            // 而上述this.reader.loadBeanDefinitions(configClasses);代碼
            // 只是將配置類中導入的類注冊到bean工廠中去,而此時有可能
            // 這些導入的類內部也會導入其他的類,所以還需要比較下當前解析的配置類
            // 中導入的類的數量和原來獲取的配置類的數量。將多出來的配置類數量進行
            // 匯總,然后再統一處理它們
            if (registry.getBeanDefinitionCount() > candidateNames.length) {
                String[] newCandidateNames = registry.getBeanDefinitionNames();
                Set<String> oldCandidateNames = new HashSet<>(Arrays.asList(candidateNames));
                Set<String> alreadyParsedClasses = new HashSet<>();
                for (ConfigurationClass configurationClass : alreadyParsed) {
                    alreadyParsedClasses.add(configurationClass.getMetadata().getClassName());
                }
                for (String candidateName : newCandidateNames) {
                    if (!oldCandidateNames.contains(candidateName)) {
                        BeanDefinition bd = registry.getBeanDefinition(candidateName);
                        if (ConfigurationClassUtils.checkConfigurationClassCandidate(bd, this.metadataReaderFactory) &&
                                !alreadyParsedClasses.contains(bd.getBeanClassName())) {
                            candidates.add(new BeanDefinitionHolder(bd, candidateName));
                        }
                    }
                }
                candidateNames = newCandidateNames;
            }
        }
        while (!candidates.isEmpty());
    
        // Register the ImportRegistry as a bean in order to support ImportAware @Configuration classes
        if (sbr != null && !sbr.containsSingleton(IMPORT_REGISTRY_BEAN_NAME)) {
            sbr.registerSingleton(IMPORT_REGISTRY_BEAN_NAME, parser.getImportRegistry());
        }
    
        if (this.metadataReaderFactory instanceof CachingMetadataReaderFactory) {
            // Clear cache in externally provided MetadataReaderFactory; this is a no-op
            // for a shared cache since it'll be cleared by the ApplicationContext.
            ((CachingMetadataReaderFactory) this.metadataReaderFactory).clearCache();
        }
    }
    
  3. 解析器ConfigurationClassParser之parser方法

    public void parse(Set<BeanDefinitionHolder> configCandidates) {
        this.deferredImportSelectors = new LinkedList<>();
    
        for (BeanDefinitionHolder holder : configCandidates) {
            BeanDefinition bd = holder.getBeanDefinition();
            try {
                // 這里會根據當前配置類的beanDefinition進入不同的解析邏輯,
                // 通過Register方法注冊的beanDefinition類型統一為AnnotatedBeanDefinition
                // 這個在之前的博客中有總結過
                if (bd instanceof AnnotatedBeanDefinition) {
                    // 所以解析配置類的時候,是進入這個if分支
                    parse(((AnnotatedBeanDefinition) bd).getMetadata(), holder.getBeanName());
                }
                else if (bd instanceof AbstractBeanDefinition && ((AbstractBeanDefinition) bd).hasBeanClass()) {
                    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);
            }
        }
    
        processDeferredImportSelectors();
    }
    
  4. 解析器ConfigurationClassParser之processConfigurationClass方法 => 會將處理的當前配置類存入解析器的configurationClasses集合中

    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()) {
                    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);
                this.knownSuperclasses.values().removeIf(configClass::equals);
            }
        }
    
        // Recursively process the configuration class and its superclass hierarchy.
        SourceClass sourceClass = asSourceClass(configClass);
        do {
            // 處理完當前配置類后, 會在方法中return null => 表示當前配置類被解析完成
            // 進而進入下面的邏輯, 將當前配置添加到configurationClasses中
            // 并在最外部
            // org.springframework.context.annotation.ConfigurationClassPostProcessor類
            // 中的processConfigBeanDefinitions方法中獲取configurationClasses, 并
            // 解析它們(這里的解析不僅僅是注冊beanDefinition, 還包括當前配置類中的
            // @Bean方法、@Import注解導入的類等等)
            sourceClass = doProcessConfigurationClass(configClass, sourceClass);
        }
        while (sourceClass != null);
    
        // 上面每次解析完配置類就添加到當前對象的configurationClasses屬性中
        // 當前對象 => 就是在
        // org.springframework.context.annotation.ConfigurationClassPostProcessor類中
        // 的processConfigBeanDefinitions方法中創建出來的配置類解析器
        this.configurationClasses.put(configClass, configClass);
    }
    
  5. 解析器ConfigurationClassParser之doProcessConfigurationClass方法 => 處理@PropertySource, @ComponentScan, @Import, @ImportResource, @Bean注解

    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注解, sourceClass為當前解析的配置類, 即: AppConfig,
        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) {
                // The config class is annotated with @ComponentScan -> perform the scan immediately
                // 掃描得到所有擁有@Component注解的beanDefinition, 并在
                // 內部(this.componentScanParser.parse)將它們注冊到bean工廠
                Set<BeanDefinitionHolder> scannedBeanDefinitions =
                        this.componentScanParser.parse(componentScan, sourceClass.getMetadata().getClassName());
                // Check the set of scanned definitions for any further config classes and parse recursively if needed
                for (BeanDefinitionHolder holder : scannedBeanDefinitions) {
                    BeanDefinition bdCand = holder.getBeanDefinition().getOriginatingBeanDefinition();
                    if (bdCand == null) {
                        bdCand = holder.getBeanDefinition();
                    }
                    // 在此校驗掃描出來的@Component注解對應的beanDefinition, 因為有可能它們也被添加了配置類相關的注解,
                    // 所以也把它們當做配置類來解析
                    // 又因為@Component注解標識的類屬于部分配置類, 所以肯定會將它們當做配置類再解析一遍
                    if (ConfigurationClassUtils.checkConfigurationClassCandidate(bdCand, this.metadataReaderFactory)) {
                        // 這里又調用了解析配置類邏輯, 遞歸調用
                        parse(bdCand.getBeanClassName(), holder.getBeanName());
                    }
                }
            }
        }
    
        // Process any @Import annotations
        // 處理當前配置類的@Import注解
        // 該方法的主要邏輯為如下:
        // 獲取@Import注解的值, 并挨個遍歷它們
    
        /*for (SourceClass candidate : importCandidates) {
    
            // 若導入的類是ImportSelector的類型
            if (candidate.isAssignable(ImportSelector.class)) {
                // Candidate class is an ImportSelector -> delegate to it to determine imports
                Class<?> candidateClass = candidate.loadClass();
    
                // 使用反射創建對象, 為了調用ImportSelector的方法
                ImportSelector selector = BeanUtils.instantiateClass(candidateClass, ImportSelector.class);
    
                ParserStrategyUtils.invokeAwareMethods(
                        selector, this.environment, this.resourceLoader, this.registry);
    
                // 判斷是否為延遲導入, 默認為null, 所有走else
                if (this.deferredImportSelectors != null && selector instanceof DeferredImportSelector) {
                    this.deferredImportSelectors.add(
                            new DeferredImportSelectorHolder(configClass, (DeferredImportSelector) selector));
                }
                else {
                    // 調用ImportSelector的selectImports方法, 得到返回的數組
                    String[] importClassNames = selector.selectImports(currentSourceClass.getMetadata());
                    // 將類對應的全路徑轉成Collection<SourceClass>類型, 為了下面的遞歸調用
                    Collection<SourceClass> importSourceClasses = asSourceClasses(importClassNames);
                    // 針對獲取到的類的全路徑, 把它們當做Import注解導入的類進行處理, 遞歸調用
                    processImports(configClass, currentSourceClass, importSourceClasses, false);
                }
            }
            // 處理類型為ImportBeanDefinitionRegistrar的類
            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);
    
                // 將導入的ImportBeanDefinitionRegistrar類型的類添加到當前配置類存放ImportBeanDefinitionRegistrar
                // 類型的集合中, 方便后面處理配置類時能獲取到它們
                configClass.addImportBeanDefinitionRegistrar(registrar, currentSourceClass.getMetadata());
            }
            else {
                // 非ImportSelector和ImportSelector的selectImports類型的類, 把它當成配置類處理
                // 在遞歸調用處理配置類邏輯processConfigurationClass
                // 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));
            }
        }*/
        processImports(configClass, sourceClass, getImports(sourceClass), true);
    
        // Process any @ImportResource annotations
        // 基于注解的方式的spring, 很少使用此注解, 所以這塊沒有總結到
        AnnotationAttributes importResource =
                AnnotationConfigUtils.attributesFor(sourceClass.getMetadata(), ImportResource.class);
        if (importResource != null) {
            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注解的情況, 挨個遍歷存放到當前配置類的數據結構中
        // 方便在外部處理配置類(loadBeanDefinition)時將它們獲取出來
        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
        // 沒總結到, 暫時忽略
        if (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 recurse
                return sourceClass.getSuperClass();
            }
        }
    
        // No superclass -> processing is complete
        return null;
    }
    
  6. 加載配置類之loadBeanDefinitions方法

    public void loadBeanDefinitions(Set<ConfigurationClass> configurationModel) {
        TrackedConditionEvaluator trackedConditionEvaluator = new TrackedConditionEvaluator();
        // 遍歷傳入的配置類集合
        for (ConfigurationClass configClass : configurationModel) {
            loadBeanDefinitionsForConfigurationClass(configClass, trackedConditionEvaluator);
        }
    }
    
    
  7. 加載配置類之loadBeanDefinitionsForConfigurationClass方法

    private void loadBeanDefinitionsForConfigurationClass(
            ConfigurationClass configClass, TrackedConditionEvaluator trackedConditionEvaluator) {
    
        if (trackedConditionEvaluator.shouldSkip(configClass)) {
            String beanName = configClass.getBeanName();
            if (StringUtils.hasLength(beanName) && this.registry.containsBeanDefinition(beanName)) {
                this.registry.removeBeanDefinition(beanName);
            }
            this.importRegistry.removeImportingClass(configClass.getMetadata().getClassName());
            return;
        }
    
        // 處理被@Import注解導入的普通類
        if (configClass.isImported()) {
            registerBeanDefinitionForImportedConfigurationClass(configClass);
        }
    
        // 處理當前配置類中的所有@Bean標識的方法, 并將它注冊到bean工廠
        for (BeanMethod beanMethod : configClass.getBeanMethods()) {
            loadBeanDefinitionsForBeanMethod(beanMethod);
        }
    
        // 加載@ImportedResources注解導入的資源
        loadBeanDefinitionsFromImportedResources(configClass.getImportedResources());
    
        // 將@Import注解導入的ImportBeanDefinitionRegistrar類型的bean注冊到bean工廠
        loadBeanDefinitionsFromRegistrars(configClass.getImportBeanDefinitionRegistrars());
    }
    

4.2.2 ConfigurationClassPostProcessor做為BeanDefinitionRegistryPostProcessor后置處理器的執行結果

  1. 執行結果和統計


    在這里插入圖片描述

    在這里插入圖片描述
BeanDefinition Name 注冊渠道
org.springframework.context.annotation.internalConfigurationAnnotationProcessor AnnotationConfigApplicationContext無參構造方法
org.springframework.context.event.internalEventListenerFactory AnnotationConfigApplicationContext無參構造方法
userServiceImpl 解析@ComponentScan注解
testDaoInUserDaoImpl @Bean注解
testDao AppConfig類的@Bean注解
org.springframework.context.event.internalEventListenerProcessor AnnotationConfigApplicationContext無參構造方法
org.springframework.context.annotation.internalAutowiredAnnotationProcessor AnnotationConfigApplicationContext無參構造方法
org.springframework.context.annotation.internalCommonAnnotationProcessor AnnotationConfigApplicationContext無參構造方法
appConfig register方法
userDaoImpl 解析@ComponentScan注解
JDKProxyPostProcessor 解析@Import注解
org.springframework.context.annotation.internalRequiredAnnotationProcessor AnnotationConfigApplicationContext無參構造方法
com.eugene.sumarry.csdn.invokeBeanFactoryPostProcessor2.postprocessor.ImportEugeneBeanFactoryProcessor 解析@Import注解

五、小結

5.1 黑箱理論

  • ConfigurationClassPostProcessor之BeanDefinitionRegistryPostProcessor身份的主要作用為:
        掃描并解析register方法注冊的配置類, 解析完成后, 所有能被掃描出來的
        bean全部都以beanDefinition的形式存在于bean工廠中,為后續執行掃描
        出來的后置處理器和創建bean提供了條件
    

5.2 建議

  • 本篇博客提供的大多數為源碼注釋, 最好是能自己手動搭建與本次demo一樣的項目結構, 結合提供的注釋和運行結果一步一步的去了解ConfigurationClassPostProcessor作為BeanDefinitionRegistryPostProcessor身份的作用
  • I am a slow walker, but I never walk backwards.
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,546評論 6 533
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,570評論 3 418
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 176,505評論 0 376
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,017評論 1 313
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,786評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,219評論 1 324
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,287評論 3 441
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,438評論 0 288
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,971評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,796評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,995評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,540評論 5 359
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,230評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,662評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,918評論 1 286
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,697評論 3 392
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,991評論 2 374

推薦閱讀更多精彩內容