ConfigurationClassPostProcessor 是 Spring 框架中实现注解驱动配置的核心后置处理器。它负责解析所有带有 @Configuration 注解的类,处理其中的 @Bean 方法、@ComponentScan@Import@ImportResource 等注解,并将解析出的新 Bean 定义注册到容器中。可以说,它是 Spring 从 XML 配置转向注解配置的基石。

一、类定义与接口实现

public class ConfigurationClassPostProcessor implements BeanDefinitionRegistryPostProcessor,
        PriorityOrdered, ResourceLoaderAware, BeanClassLoaderAware, EnvironmentAware
  • BeanDefinitionRegistryPostProcessor:继承自 BeanFactoryPostProcessor,允许在标准 BeanFactoryPostProcessor 执行之前向容器注册额外的 Bean 定义。ConfigurationClassPostProcessor 正是利用这个接口在容器刷新的早期阶段处理配置类。

  • PriorityOrdered:拥有最高优先级,确保它比其他后置处理器更早执行。

  • ResourceLoaderAwareBeanClassLoaderAwareEnvironmentAware:注入所需的基础设施对象。


二、核心方法:postProcessBeanDefinitionRegistry

这是 ConfigurationClassPostProcessor 的入口,在容器 refresh() 的 invokeBeanFactoryPostProcessors 阶段被调用。

@Override
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) {
    // 生成一个哈希值,用于检测重复执行
    int registryId = System.identityHashCode(registry);
    if (this.registriesPostProcessed.contains(registryId)) {
        throw new IllegalStateException("...");
    }
    if (this.factoriesPostProcessed.contains(registryId)) {
        throw new IllegalStateException("...");
    }
    this.registriesPostProcessed.add(registryId);

    // 核心处理逻辑
    processConfigBeanDefinitions(registry);
}

processConfigBeanDefinitions 方法

这个方法包含了处理配置类的完整逻辑:

public void processConfigBeanDefinitions(BeanDefinitionRegistry registry) {
    List<BeanDefinitionHolder> configCandidates = new ArrayList<>();
    // 获取容器中所有已注册的 Bean 名称
    String[] candidateNames = registry.getBeanDefinitionNames();

    // 遍历所有 BeanDefinition,找出候选的配置类
    for (String beanName : candidateNames) {
        BeanDefinition beanDef = registry.getBeanDefinition(beanName);
        // 检查是否是 Full 或 Lite 配置类
        if (ConfigurationClassUtils.isFullConfigurationClass(beanDef) ||
                ConfigurationClassUtils.isLiteConfigurationClass(beanDef)) {
            // 如果已经处理过(标记了属性),则跳过,避免重复处理
            if (logger.isDebugEnabled()) {
                logger.debug("Bean definition has already been processed as a configuration class: " + beanName);
            }
        }
        // 检查是否符合配置类的条件(带有 @Configuration 或 @Bean 方法、@Component 等)
        else if (ConfigurationClassUtils.checkConfigurationClassCandidate(beanDef, this.metadataReaderFactory)) {
            configCandidates.add(new BeanDefinitionHolder(beanDef, beanName));
        }
    }

    // 如果没有找到任何配置类,直接返回
    if (configCandidates.isEmpty()) {
        return;
    }

    // 对配置类按照 @Order 注解进行排序
    configCandidates.sort((bd1, bd2) -> {
        int i1 = ConfigurationClassUtils.getOrder(bd1.getBeanDefinition());
        int i2 = ConfigurationClassUtils.getOrder(bd2.getBeanDefinition());
        return Integer.compare(i1, i2);
    });

    // 创建解析器需要的组件
    SingletonBeanRegistry sbr = null;
    if (registry instanceof SingletonBeanRegistry) {
        sbr = (SingletonBeanRegistry) registry;
        if (!this.localBeanNameGeneratorSet) {
            // 检查是否已存在自定义的 BeanNameGenerator
            BeanNameGenerator generator = (BeanNameGenerator) sbr.getSingleton(
                    AnnotationConfigUtils.CONFIGURATION_BEAN_NAME_GENERATOR);
            if (generator != null) {
                this.componentScanBeanNameGenerator = generator;
                this.importBeanNameGenerator = generator;
            }
        }
    }

    // 初始化环境
    if (this.environment == null) {
        this.environment = new StandardEnvironment();
    }

    // 创建配置类解析器
    ConfigurationClassParser 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 {
        // 1. 解析配置类(核心)
        parser.parse(candidates);
        parser.validate();

        // 获取解析出的所有配置类(包括递归解析出的)
        Set<ConfigurationClass> configClasses = new LinkedHashSet<>(parser.getConfigurationClasses());
        configClasses.removeAll(alreadyParsed);

        // 2. 读取配置类,生成 BeanDefinition
        if (this.reader == null) {
            this.reader = new ConfigurationClassBeanDefinitionReader(
                    registry, this.sourceExtractor, this.resourceLoader, this.environment,
                    this.importBeanNameGenerator, parser.getImportRegistry());
        }
        this.reader.loadBeanDefinitions(configClasses);

        // 将已解析的加入集合
        alreadyParsed.addAll(configClasses);

        // 清空候选列表,准备处理新注册的配置类
        candidates.clear();
        // 如果当前 registry 中的 BeanDefinition 数量大于之前,说明有新的配置类被注册(例如通过 @Import 引入的)
        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()); // 循环直到没有新配置类出现

    // 将处理标记存入 BeanDefinition,防止重复处理
    for (BeanDefinitionHolder holder : configCandidates) {
        ConfigurationClassUtils.setConfigurationClassAttribute(holder.getBeanDefinition(),
                parser.getConfigurationClasses().contains(holder.getBeanDefinition().getBeanClassName()));
    }

    // 可选:将 ImportRegistry 注册为单例 Bean,以便在运行时查询导入信息
    if (sbr != null && !sbr.containsSingleton(IMPORT_REGISTRY_BEAN_NAME)) {
        sbr.registerSingleton(IMPORT_REGISTRY_BEAN_NAME, parser.getImportRegistry());
    }
}

流程总结

  1. 收集候选配置类:遍历所有已注册的 BeanDefinition,通过 ConfigurationClassUtils.checkConfigurationClassCandidate 判断是否是配置类(Full 或 Lite)。

  2. 排序:按 @Order 排序。

  3. 创建解析器ConfigurationClassParser 负责解析配置类。

  4. 循环解析

    • parser.parse(candidates) 解析当前候选配置类(会递归处理 @ComponentScan@Import 等)。

    • 获取所有解析出的 ConfigurationClass

    • 使用 reader.loadBeanDefinitions(configClasses) 将解析结果注册为 BeanDefinition

    • 检查是否有新的配置类被注册(例如通过 @Import 引入的普通类,或者 @ComponentScan 扫描到的配置类),如果有,则继续下一轮循环。

  5. 清理与标记:标记已处理的 BeanDefinition,避免重复处理。

  6. 注册 ImportRegistry:供运行时查询导入信息。


三、ConfigurationClassUtils 工具类

ConfigurationClassUtils 提供了几个静态方法用于判断和标记配置类:

  • checkConfigurationClassCandidate:判断一个 BeanDefinition 是否是配置类候选。

    • 如果类上有 @Configuration 注解,则为 Full 配置类configurationClass 属性设为 "full")。

    • 如果类上有 @Component@ComponentScan@Import@ImportResource 注解,或者类中有 @Bean 方法,则为 Lite 配置类configurationClass 属性设为 "lite")。

    • 否则不是配置类。

  • isFullConfigurationClass / isLiteConfigurationClass:检查 BeanDefinition 的 configurationClass 属性值。

  • getOrder:获取配置类的 @Order 值,用于排序。


四、ConfigurationClassParser 解析器

ConfigurationClassParser 是真正解析配置类的核心。它的 parse 方法接收一组候选配置类,然后逐个调用 processConfigurationClass 进行解析。

processConfigurationClass 方法

protected void processConfigurationClass(ConfigurationClass configClass) throws IOException {
    // 条件评估:如果 @Conditional 条件不满足,则跳过
    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()) {
                // 如果同一个类被多次导入,合并导入的 Bean 定义
                existingClass.mergeImportedBy(configClass);
            }
            // 否则,已经存在的非导入类优先级更高,忽略导入的
            return;
        }
        else {
            // 显式注册的配置类会覆盖导入的
            this.configurationClasses.remove(configClass);
            this.knownSuperclasses.values().removeIf(configClass::equals);
        }
    }

    // 递归解析配置类及其父类
    SourceClass sourceClass = asSourceClass(configClass);
    do {
        sourceClass = doProcessConfigurationClass(configClass, sourceClass);
    }
    while (sourceClass != null);

    // 将解析后的配置类存入 Map
    this.configurationClasses.put(configClass, configClass);
}

doProcessConfigurationClass 核心递归方法

这个方法按顺序处理配置类上的各种注解,返回父类的 SourceClass 以便继续递归。

protected final SourceClass doProcessConfigurationClass(
        ConfigurationClass configClass, SourceClass sourceClass) throws IOException {

    // 1. 处理内部类(如果内部类也是配置类,递归处理)
    processMemberClasses(configClass, sourceClass);

    // 2. 处理 @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.info("Ignoring @PropertySource annotation on [" + sourceClass.getMetadata().getClassName() +
                    "] because 'environment' is not configurable");
        }
    }

    // 3. 处理 @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) {
            // 执行扫描,将扫描到的 BeanDefinition 注册到容器,并返回扫描到的配置类
            Set<BeanDefinitionHolder> scannedBeanDefinitions =
                    this.componentScanParser.parse(componentScan, sourceClass.getMetadata().getClassName());
            // 检查扫描到的类中是否还有配置类,如果有,需要继续解析
            for (BeanDefinitionHolder holder : scannedBeanDefinitions) {
                BeanDefinition bdCand = holder.getBeanDefinition().getOriginatingBeanDefinition();
                if (bdCand == null) {
                    bdCand = holder.getBeanDefinition();
                }
                if (ConfigurationClassUtils.checkConfigurationClassCandidate(bdCand, this.metadataReaderFactory)) {
                    // 递归解析扫描到的配置类
                    parse(bdCand.getBeanClassName(), holder.getBeanName());
                }
            }
        }
    }

    // 4. 处理 @Import 注解
    processImports(configClass, sourceClass, getImports(sourceClass), true);

    // 5. 处理 @ImportResource 注解
    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);
        }
    }

    // 6. 处理 @Bean 方法
    Set<MethodMetadata> beanMethods = retrieveBeanMethodMetadata(sourceClass);
    for (MethodMetadata methodMetadata : beanMethods) {
        configClass.addBeanMethod(new BeanMethod(methodMetadata, configClass));
    }

    // 7. 处理接口上的默认方法(如果有 @Bean 方法)
    processInterfaces(configClass, sourceClass);

    // 8. 处理父类(如果有)
    if (sourceClass.getMetadata().hasSuperClass()) {
        String superclass = sourceClass.getMetadata().getSuperClassName();
        if (superclass != null && !superclass.startsWith("java") &&
                !this.knownSuperclasses.containsKey(superclass)) {
            this.knownSuperclasses.put(superclass, configClass);
            // 返回父类的 SourceClass,外层循环会继续解析
            return sourceClass.getSuperClass();
        }
    }

    // 没有父类需要处理,返回 null 终止循环
    return null;
}

处理顺序的重要性:例如,@ComponentScan 必须在 @Bean 之前处理,因为扫描可能发现新的配置类,而这些配置类内部可能包含 @Bean 方法。@Import 在 @Bean 之前,因为导入的类也可能是配置类。

processImports 方法

处理 @Import 注解是 Spring 扩展机制的核心。@Import 可以导入三种类型:

  • 普通配置类:递归解析。

  • ImportSelector:调用 selectImports 方法,获取要导入的类名,然后递归处理这些类。

  • ImportBeanDefinitionRegistrar:暂存起来,等所有配置类解析完成后,由 ConfigurationClassBeanDefinitionReader 调用其 registerBeanDefinitions 方法。

private void processImports(ConfigurationClass configClass, SourceClass currentSourceClass,
        Collection<SourceClass> importCandidates, boolean checkForCircularImports) {

    if (importCandidates.isEmpty()) {
        return;
    }

    if (checkForCircularImports && isChainedImportOnStack(configClass)) {
        this.problemReporter.error(new CircularImportProblem(configClass, this.importStack));
    }
    else {
        this.importStack.push(configClass);
        try {
            for (SourceClass candidate : importCandidates) {
                if (candidate.isAssignable(ImportSelector.class)) {
                    // 导入的是 ImportSelector
                    Class<?> candidateClass = candidate.loadClass();
                    ImportSelector selector = BeanUtils.instantiateClass(candidateClass, ImportSelector.class);
                    ParserStrategyUtils.invokeAwareMethods(
                            selector, this.environment, this.resourceLoader, this.registry);
                    if (selector instanceof DeferredImportSelector) {
                        // DeferredImportSelector 暂不处理,等到所有配置类解析完后统一处理
                        this.deferredImportSelectorHandler.handle(configClass, (DeferredImportSelector) selector);
                    }
                    else {
                        // 普通 ImportSelector,立即执行 selectImports
                        String[] importClassNames = selector.selectImports(currentSourceClass.getMetadata());
                        Collection<SourceClass> importSourceClasses = asSourceClasses(importClassNames);
                        // 递归处理这些导入的类
                        processImports(configClass, currentSourceClass, importSourceClasses, false);
                    }
                }
                else if (candidate.isAssignable(ImportBeanDefinitionRegistrar.class)) {
                    // 导入的是 ImportBeanDefinitionRegistrar,暂存到配置类中
                    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 {
                    // 导入的是普通配置类,将当前导入栈信息附加后递归解析
                    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();
        }
    }
}

注意DeferredImportSelector 会被延迟到所有配置类解析完成后,按照 @Order 排序后再统一处理。这解决了某些导入需要依赖其他配置类的场景(例如 Spring Boot 的自动配置)。


五、ConfigurationClassBeanDefinitionReader 读取器

当所有配置类解析完成后,reader.loadBeanDefinitions(configClasses) 负责将解析结果注册为 BeanDefinition。

loadBeanDefinitionsForConfigurationClass 方法

private void loadBeanDefinitionsForConfigurationClass(
        ConfigurationClass configClass, TrackedConditionEvaluator trackedConditionEvaluator) {

    // 条件评估:再次检查 @Conditional
    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;
    }

    if (configClass.isImported()) {
        // 如果是被导入的,注册它自己(有可能被 ImportBeanDefinitionRegistrar 处理,但这里注册是为了让它的 @Bean 方法生效)
        registerBeanDefinitionForImportedConfigurationClass(configClass);
    }
    // 处理 @Bean 方法
    for (BeanMethod beanMethod : configClass.getBeanMethods()) {
        loadBeanDefinitionsForBeanMethod(beanMethod);
    }
    // 处理 @ImportResource 引入的 XML
    loadBeanDefinitionsFromImportedResources(configClass.getImportedResources());
    // 处理 ImportBeanDefinitionRegistrar
    loadBeanDefinitionsFromRegistrars(configClass.getImportBeanDefinitionRegistrars());
}

loadBeanDefinitionsForBeanMethod

这个方法将 @Bean 方法转换为 BeanDefinition,并设置相关属性(工厂方法名、工厂 Bean 名称、参数依赖等)。

private void loadBeanDefinitionsForBeanMethod(BeanMethod beanMethod) {
    ConfigurationClass configClass = beanMethod.getConfigurationClass();
    MethodMetadata metadata = beanMethod.getMetadata();
    String methodName = metadata.getMethodName();

    // 创建 BeanDefinition
    ConfigurationClassBeanDefinition beanDef = new ConfigurationClassBeanDefinition(configClass, metadata);
    beanDef.setResource(configClass.getResource());
    beanDef.setSource(this.sourceExtractor.extractSource(metadata, configClass.getResource()));

    // 设置作用域
    String scope = determineScopeName(metadata);
    if (scope == null) {
        scope = BeanDefinition.SCOPE_SINGLETON;
    }
    beanDef.setScope(scope);

    // 设置工厂相关信息
    beanDef.setFactoryBeanName(configClass.getBeanName());
    beanDef.setFactoryMethodName(methodName);

    // 设置参数依赖
    // ... 省略参数处理细节

    // 设置其他注解属性(@Lazy, @Primary, @DependsOn, @Role, @Description)
    AnnotationConfigUtils.processCommonDefinitionAnnotations(beanDef, metadata);

    // 验证和注册
    Autowire autowire = (BeanDefinition.AUTOWIRE_CONSTRUCTOR == beanDef.getAutowireMode() ?
            Autowire.CONSTRUCTOR : Autowire.BY_NAME);
    String qualifier = determineAutowireCandidate(metadata);
    // ... 省略注册细节
}

registerBeanDefinitionForImportedConfigurationClass

为被导入的配置类本身注册一个 BeanDefinition。这通常是因为配置类被 @Import 引入,需要作为一个 Bean 存在(以便其内部的 @Bean 方法能被调用)。


六、Full 模式与 Lite 模式的区别

  • Full 模式:类上标注了 @Configuration(proxyBeanMethods = true)(默认)。Spring 会通过 CGLIB 为该类创建代理,拦截 @Bean 方法的调用,确保每次调用返回的都是同一个单例 Bean。这样可以保证在配置类内部直接调用 @Bean 方法时,不会创建多个实例。

  • Lite 模式:类上没有 @Configuration,或者设置了 proxyBeanMethods = false。Spring 不会代理该类,@Bean 方法会被当作普通工厂方法处理,调用它们会直接执行方法体,可能导致重复创建。Lite 模式的配置类包括带有 @Component@ComponentScan@Import@ImportResource 的类,以及包含 @Bean 方法的普通类。

ConfigurationClassPostProcessor 会根据 checkConfigurationClassCandidate 中判断出的类型,在解析过程中决定是否要为其生成代理。具体的代理逻辑并不在 ConfigurationClassPostProcessor 中,而是在 @Configuration 类被实例化时,由 ConfigurationClassEnhancer 生成增强子类。


七、其他内部类

  • ConfigurationClass:代表一个解析后的配置类,包含其元数据、导入的资源配置、@Bean 方法集合、ImportBeanDefinitionRegistrar 列表等。

  • BeanMethod:封装一个 @Bean 方法,包含方法元数据和所属配置类。

  • DeferredImportSelectorHandler:延迟处理 DeferredImportSelector,按组排序后处理。

  • ImportStack:用于检测循环导入。


八、总结

ConfigurationClassPostProcessor 是 Spring 注解驱动的基石,它的核心职责可以概括为:

  1. 识别配置类:通过 @Configuration@Bean 等注解识别所有配置类。

  2. 递归解析:处理配置类上的 @ComponentScan@Import@Bean 等注解,生成完整的配置类模型。

  3. 注册 Bean 定义:将解析出的所有 @Bean 方法、导入的配置类、ImportBeanDefinitionRegistrar 动态注册的 Bean 定义,注册到容器中。

  4. 支持条件化配置:通过 @Conditional 注解,在解析和注册阶段进行条件判断。

  5. 实现 Full 模式代理:为 @Configuration 类生成 CGLIB 代理,保证单例语义。

理解 ConfigurationClassPostProcessor 的工作原理,有助于深入掌握 Spring 的内部扩展机制,以及如何利用 @ImportImportSelectorImportBeanDefinitionRegistrar 实现模块化配置和自动装配。

Logo

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐