You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

@Primary标注的Bean未生效,是否必须为默认Bean添加@ConditionalOnMissingBean?

结论

这个行为完全符合Spring的设计逻辑,你没有遗漏基础配置,核心问题出在同名称Bean的注册规则和@Primary的生效前提上。


根因分析

  • @Primary的生效前提是容器中同时存在多个同类型的Bean,此时在没有指定@Qualifier的注入场景下,Spring会优先选择标记了@Primary的Bean。
  • 你的两个配置类中定义的Bean方法名完全相同,Spring默认使用方法名作为Bean名称,所以两个配置类生成的是同名称、同类型的Bean定义。
  • Spring Boot 2.1+版本默认spring.main.allow-bean-definition-overriding为false,同名称Bean不会覆盖,只会保留先被扫描到的那个;如果你的版本允许Bean覆盖,则会保留后被扫描到的那个。由于checkout-library-impl的Jar包默认在classpath中的排序早于checkout-library-test,所以最终容器中只会存在默认的非@Primary的Bean,@Primary自然不会生效。
  • 你给默认Bean加上@ConditionalOnMissingBean后,默认Bean注册前会先检查是否已有同类型Bean存在,如果Test配置类的Bean已完成注册,默认Bean就会跳过注册,此时容器中只有Test的@Primary Bean,所以可以正常使用。

无需修改默认配置的解决方案

你不想加@ConditionalOnMissingBean也不想做starter,可以用以下两种方案实现需求:

  1. 修改Test配置类的Bean方法名(最推荐)
    把Test配置类里的Bean方法名改得和默认配置不一样,避免同名称Bean冲突,这样两个同类型的Bean都会被正常注册到容器中,@Primary注解会自动生效,优先选择Test的Bean:
package com.name.core.checkout.config;

@Configuration
@PropertySource("classpath:checkout-test.properties")
public class TestCheckoutConfiguration {

    @Bean
    @Primary
    CheckoutClient testCheckoutClient(final CheckoutClientConfig config) {
        // ...
    }

    @Bean
    @Primary
    public CheckoutManager testCheckoutManager(final CheckoutClient checkoutClient) {
        return new TestCheckoutManagerImpl(checkoutClient);
    }
}
  1. 配置Bean覆盖规则(可选,不推荐)
    在application.properties中添加配置开启Bean覆盖,同时调整checkout-library-test的Jar包依赖顺序在checkout-library-impl之前,保证Test的Bean后注册覆盖默认Bean:
spring.main.allow-bean-definition-overriding=true

该方案的缺点是依赖Jar包顺序,可移植性差,且开启全局Bean覆盖可能带来其他不可预期的问题。


内容的提问来源于stack exchange,提问作者filpa

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.05 23:54:04