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

前言

一专筷、ConfigurationClassPostProcessor之BeanDefinitionRegistryPostProcessor身份

  • 它的這個身份起到了非常重要的作用: 處理配置類并解析它們于未。 這句話可能有點(diǎn)難理解, 我們根據(jù)下面的篇幅慢慢理解撕攒。

二、流程圖

  • 這里提供一張?zhí)幚砼渲妙惲鞒虉D, 結(jié)合項(xiàng)目demo一起看


    在這里插入圖片描述

三烘浦、項(xiàng)目demo

3.1 項(xiàng)目全景圖

在這里插入圖片描述

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運(yùn)行結(jié)果

  1. AppConfig存在@ImportEugene@EnableProxy注解時, 運(yùn)行結(jié)果如下:

    在這里插入圖片描述

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

  2. AppConfig去除@ImportEugene@EnableProxy注解時, 運(yùn)行結(jié)果如下:

    在這里插入圖片描述

    在這里插入圖片描述

    在這里插入圖片描述

3.4 Demo運(yùn)行結(jié)果總結(jié)

  • 本demo利用了spring的兩個大擴(kuò)展點(diǎn): BeanPostProcessor@Import注解抖坪。其中自定義注解 @EnableProxy@ImportEugene利用了 @Import注解擴(kuò)展點(diǎn)的兩種類型: ImportSelectorImportBeanDefinitionRegistrar來實(shí)現(xiàn)

  • 關(guān)于上述的三個點(diǎn)BeanPostProcessor, ImportSelector, ImportSelector的功能將以如下表格來闡述

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

四、運(yùn)行原理

4.1 前言

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

4.2 執(zhí)行原理

4.2.1 在上篇博客中有總結(jié)到invokeBeanFactoryPostProcessors方法執(zhí)行后置處理器的幾個順序闷叉。我們現(xiàn)在將從調(diào)用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) {
        // 存儲配置類的數(shù)據(jù)結(jié)構(gòu): 很重要, 后續(xù)將解析此集合
        List<BeanDefinitionHolder> configCandidates = new ArrayList<>();
    
        // 獲取bean工廠的所有beanDefinition的名稱, 在本次demo中, 一共有7個beanDefinition
        // 為spring內(nèi)置的6個beanDefinition + AppConfig beanDefinition
        String[] candidateNames = registry.getBeanDefinitionNames();
    
        // 遍歷beanDefinition
        for (String beanName : candidateNames) {
    
            // 根據(jù)beanName到bean工廠中拿到beanDefinition
            BeanDefinition beanDef = registry.getBeanDefinition(beanName);
    
            // 判斷是否為全注解或者部分注解  => 這里正常的spring流程下, 應(yīng)該都沒標(biāo)注
            // 除非程序員自己利用擴(kuò)展點(diǎn)修改了配置類對應(yīng)的標(biāo)識
            // eg: 標(biāo)識它為全配置類
            // 配置類對應(yīng)的beanDefinition.setAttribute(
            // "org.springframework.context.annotation.
            // ConfigurationClassPostProcessor.configurationClass", "full");
            // eg: 標(biāo)識它為部分配置類
            // 配置類對應(yīng)的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的核心邏輯應(yīng)該為如下代碼
            // if (isFullConfigurationCandidate(metadata)) {
            //     beanDef.setAttribute(CONFIGURATION_CLASS_ATTRIBUTE, CONFIGURATION_CLASS_FULL);
            // }
            // else if (isLiteConfigurationCandidate(metadata)) {
            //     beanDef.setAttribute(CONFIGURATION_CLASS_ATTRIBUTE, CONFIGURATION_CLASS_LITE);
            // }
            // 若當(dāng)前遍歷的beanDefinition是一個配置類或者全配置類則給他一個標(biāo)識, 并返回true
            // 進(jìn)而將當(dāng)前的beanDefinition添加到configCandidates數(shù)據(jù)結(jié)構(gòu)中
            // 這里總結(jié)下什么叫全配置類什么叫部分配置類
            // 全配置類: 加了@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工廠中無配置類, 那么將結(jié)束解析配置類的流程
        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
        // 還未總結(jié)到它的具體作用
        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
        // 生成一個配置類的解析器, 將使用它來對配置類進(jìn)行解析
        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擴(kuò)展點(diǎn)手動添加到bean工廠的配置類添加到存放解析完畢的數(shù)據(jù)結(jié)構(gòu)中,
        // 為什么這么做蚯瞧? 因?yàn)楹罄m(xù)將挨個去解析candidates的配置類, 并將新掃描出來或者import進(jìn)去的
        // 配置類也添加到candidates里面去了, 不需要再解析一遍
        Set<ConfigurationClass> alreadyParsed = new HashSet<>(configCandidates.size());
    
        do {
            // 解析配置類, 執(zhí)行到此, candidates中只有一個元素,
            // 因?yàn)樵趫?zhí)行這個步驟的時候只有AppConfig對應(yīng)的beanDefinition在bean工廠中
            parser.parse(candidates);
            parser.validate();
    
            // 拿到配置類解析器得到的配置類
            Set<ConfigurationClass> configClasses = new LinkedHashSet<>(parser.getConfigurationClasses());
    
            // 移出已經(jīng)解析的配置類
            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工廠中
            // 所以執(zhí)行到這里時, configClasses中存儲元素內(nèi)容應(yīng)該為:
            // 根據(jù)candidates中的配置類解析出來的所有配置類
            // (包括@Component注解的類、@Import注解導(dǎo)入的普通類品擎、@Configuration的類)
            this.reader.loadBeanDefinitions(configClasses);
            alreadyParsed.addAll(configClasses);
    
            candidates.clear();
            // 這里還會校驗(yàn)這樣一種情況埋合,因?yàn)樗信渲妙愂谴娴絚andidates變量中
            // 而上述this.reader.loadBeanDefinitions(configClasses);代碼
            // 只是將配置類中導(dǎo)入的類注冊到bean工廠中去,而此時有可能
            // 這些導(dǎo)入的類內(nèi)部也會導(dǎo)入其他的類萄传,所以還需要比較下當(dāng)前解析的配置類
            // 中導(dǎo)入的類的數(shù)量和原來獲取的配置類的數(shù)量饥悴。將多出來的配置類數(shù)量進(jìn)行
            // 匯總,然后再統(tǒng)一處理它們
            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 {
                // 這里會根據(jù)當(dāng)前配置類的beanDefinition進(jìn)入不同的解析邏輯,
                // 通過Register方法注冊的beanDefinition類型統(tǒng)一為AnnotatedBeanDefinition
                // 這個在之前的博客中有總結(jié)過
                if (bd instanceof AnnotatedBeanDefinition) {
                    // 所以解析配置類的時候,是進(jìn)入這個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方法 => 會將處理的當(dāng)前配置類存入解析器的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 {
            // 處理完當(dāng)前配置類后, 會在方法中return null => 表示當(dāng)前配置類被解析完成
            // 進(jìn)而進(jìn)入下面的邏輯, 將當(dāng)前配置添加到configurationClasses中
            // 并在最外部
            // org.springframework.context.annotation.ConfigurationClassPostProcessor類
            // 中的processConfigBeanDefinitions方法中獲取configurationClasses, 并
            // 解析它們(這里的解析不僅僅是注冊beanDefinition, 還包括當(dāng)前配置類中的
            // @Bean方法西设、@Import注解導(dǎo)入的類等等)
            sourceClass = doProcessConfigurationClass(configClass, sourceClass);
        }
        while (sourceClass != null);
    
        // 上面每次解析完配置類就添加到當(dāng)前對象的configurationClasses屬性中
        // 當(dāng)前對象 => 就是在
        // org.springframework.context.annotation.ConfigurationClassPostProcessor類中
        // 的processConfigBeanDefinitions方法中創(chuàng)建出來的配置類解析器
        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為當(dāng)前解析的配置類, 即: 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, 并在
                // 內(nèi)部(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();
                    }
                    // 在此校驗(yàn)掃描出來的@Component注解對應(yīng)的beanDefinition, 因?yàn)橛锌赡芩鼈円脖惶砑恿伺渲妙愊嚓P(guān)的注解,
                    // 所以也把它們當(dāng)做配置類來解析
                    // 又因?yàn)锧Component注解標(biāo)識的類屬于部分配置類, 所以肯定會將它們當(dāng)做配置類再解析一遍
                    if (ConfigurationClassUtils.checkConfigurationClassCandidate(bdCand, this.metadataReaderFactory)) {
                        // 這里又調(diào)用了解析配置類邏輯, 遞歸調(diào)用
                        parse(bdCand.getBeanClassName(), holder.getBeanName());
                    }
                }
            }
        }
    
        // Process any @Import annotations
        // 處理當(dāng)前配置類的@Import注解
        // 該方法的主要邏輯為如下:
        // 獲取@Import注解的值, 并挨個遍歷它們
    
        /*for (SourceClass candidate : importCandidates) {
    
            // 若導(dǎo)入的類是ImportSelector的類型
            if (candidate.isAssignable(ImportSelector.class)) {
                // Candidate class is an ImportSelector -> delegate to it to determine imports
                Class<?> candidateClass = candidate.loadClass();
    
                // 使用反射創(chuàng)建對象, 為了調(diào)用ImportSelector的方法
                ImportSelector selector = BeanUtils.instantiateClass(candidateClass, ImportSelector.class);
    
                ParserStrategyUtils.invokeAwareMethods(
                        selector, this.environment, this.resourceLoader, this.registry);
    
                // 判斷是否為延遲導(dǎo)入, 默認(rèn)為null, 所有走else
                if (this.deferredImportSelectors != null && selector instanceof DeferredImportSelector) {
                    this.deferredImportSelectors.add(
                            new DeferredImportSelectorHolder(configClass, (DeferredImportSelector) selector));
                }
                else {
                    // 調(diào)用ImportSelector的selectImports方法, 得到返回的數(shù)組
                    String[] importClassNames = selector.selectImports(currentSourceClass.getMetadata());
                    // 將類對應(yīng)的全路徑轉(zhuǎn)成Collection<SourceClass>類型, 為了下面的遞歸調(diào)用
                    Collection<SourceClass> importSourceClasses = asSourceClasses(importClassNames);
                    // 針對獲取到的類的全路徑, 把它們當(dāng)做Import注解導(dǎo)入的類進(jìn)行處理, 遞歸調(diào)用
                    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();
                // 使用反射創(chuàng)建對象
                ImportBeanDefinitionRegistrar registrar =
                        BeanUtils.instantiateClass(candidateClass, ImportBeanDefinitionRegistrar.class);
    
                ParserStrategyUtils.invokeAwareMethods(
                        registrar, this.environment, this.resourceLoader, this.registry);
    
                // 將導(dǎo)入的ImportBeanDefinitionRegistrar類型的類添加到當(dāng)前配置類存放ImportBeanDefinitionRegistrar
                // 類型的集合中, 方便后面處理配置類時能獲取到它們
                configClass.addImportBeanDefinitionRegistrar(registrar, currentSourceClass.getMetadata());
            }
            else {
                // 非ImportSelector和ImportSelector的selectImports類型的類, 把它當(dāng)成配置類處理
                // 在遞歸調(diào)用處理配置類邏輯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, 很少使用此注解, 所以這塊沒有總結(jié)到
        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注解的情況, 挨個遍歷存放到當(dāng)前配置類的數(shù)據(jù)結(jié)構(gòu)中
        // 方便在外部處理配置類(loadBeanDefinition)時將它們獲取出來
        Set<MethodMetadata> beanMethods = retrieveBeanMethodMetadata(sourceClass);
        for (MethodMetadata methodMetadata : beanMethods) {
            configClass.addBeanMethod(new BeanMethod(methodMetadata, configClass));
        }
    
        // Process default methods on interfaces
        // 沒總結(jié)到, 暫時忽略
        processInterfaces(configClass, sourceClass);
    
        // Process superclass, if any
        // 沒總結(jié)到, 暫時忽略
        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注解導(dǎo)入的普通類
        if (configClass.isImported()) {
            registerBeanDefinitionForImportedConfigurationClass(configClass);
        }
    
        // 處理當(dāng)前配置類中的所有@Bean標(biāo)識的方法, 并將它注冊到bean工廠
        for (BeanMethod beanMethod : configClass.getBeanMethods()) {
            loadBeanDefinitionsForBeanMethod(beanMethod);
        }
    
        // 加載@ImportedResources注解導(dǎo)入的資源
        loadBeanDefinitionsFromImportedResources(configClass.getImportedResources());
    
        // 將@Import注解導(dǎo)入的ImportBeanDefinitionRegistrar類型的bean注冊到bean工廠
        loadBeanDefinitionsFromRegistrars(configClass.getImportBeanDefinitionRegistrars());
    }
    

4.2.2 ConfigurationClassPostProcessor做為BeanDefinitionRegistryPostProcessor后置處理器的執(zhí)行結(jié)果

  1. 執(zhí)行結(jié)果和統(tǒng)計(jì)


    在這里插入圖片描述

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

五瓣铣、小結(jié)

5.1 黑箱理論

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

5.2 建議

  • 本篇博客提供的大多數(shù)為源碼注釋, 最好是能自己手動搭建與本次demo一樣的項(xiàng)目結(jié)構(gòu), 結(jié)合提供的注釋和運(yùn)行結(jié)果一步一步的去了解ConfigurationClassPostProcessor作為BeanDefinitionRegistryPostProcessor身份的作用
  • I am a slow walker, but I never walk backwards.
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末贷揽,一起剝皮案震驚了整個濱河市棠笑,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌禽绪,老刑警劉巖蓖救,帶你破解...
    沈念sama閱讀 206,968評論 6 482
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異印屁,居然都是意外死亡循捺,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,601評論 2 382
  • 文/潘曉璐 我一進(jìn)店門雄人,熙熙樓的掌柜王于貴愁眉苦臉地迎上來从橘,“玉大人,你說我怎么就攤上這事础钠∏×Γ” “怎么了?”我有些...
    開封第一講書人閱讀 153,220評論 0 344
  • 文/不壞的土叔 我叫張陵旗吁,是天一觀的道長踩萎。 經(jīng)常有香客問我,道長很钓,這世上最難降的妖魔是什么香府? 我笑而不...
    開封第一講書人閱讀 55,416評論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮码倦,結(jié)果婚禮上回还,老公的妹妹穿的比我還像新娘。我一直安慰自己叹洲,他們只是感情好柠硕,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,425評論 5 374
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著运提,像睡著了一般蝗柔。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上民泵,一...
    開封第一講書人閱讀 49,144評論 1 285
  • 那天癣丧,我揣著相機(jī)與錄音,去河邊找鬼栈妆。 笑死胁编,一個胖子當(dāng)著我的面吹牛厢钧,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播嬉橙,決...
    沈念sama閱讀 38,432評論 3 401
  • 文/蒼蘭香墨 我猛地睜開眼早直,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了市框?” 一聲冷哼從身側(cè)響起霞扬,我...
    開封第一講書人閱讀 37,088評論 0 261
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎枫振,沒想到半個月后喻圃,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,586評論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡粪滤,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,028評論 2 325
  • 正文 我和宋清朗相戀三年斧拍,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片杖小。...
    茶點(diǎn)故事閱讀 38,137評論 1 334
  • 序言:一個原本活蹦亂跳的男人離奇死亡肆汹,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出窍侧,到底是詐尸還是另有隱情县踢,我是刑警寧澤转绷,帶...
    沈念sama閱讀 33,783評論 4 324
  • 正文 年R本政府宣布伟件,位于F島的核電站,受9級特大地震影響议经,放射性物質(zhì)發(fā)生泄漏斧账。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,343評論 3 307
  • 文/蒙蒙 一煞肾、第九天 我趴在偏房一處隱蔽的房頂上張望咧织。 院中可真熱鬧,春花似錦籍救、人聲如沸习绢。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,333評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽闪萄。三九已至,卻和暖如春奇颠,著一層夾襖步出監(jiān)牢的瞬間败去,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,559評論 1 262
  • 我被黑心中介騙來泰國打工烈拒, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留圆裕,地道東北人广鳍。 一個月前我還...
    沈念sama閱讀 45,595評論 2 355
  • 正文 我出身青樓,卻偏偏與公主長得像吓妆,于是被迫代替她去往敵國和親赊时。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,901評論 2 345

推薦閱讀更多精彩內(nèi)容