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

Spring注入报错:期望单个匹配Bean却找到2个,原因是什么?

Spring同类型多Bean注入冲突问题

场景复现

我编写了如下Spring配置类,定义了两个类型均为Set<JsonNode>的Bean:

@Configuration
public class DataQueue {

    /**
     * 存储从PLC读取的{@link SlowVars}的队列
     * @return 队列实例
     */
    @Bean
    Set<JsonNode> slowVarsQueue() {
        return new CopyOnWriteArraySet<>();
    }

    /**
     * 存储{@link JsonNode}事件的队列
     * @return 队列实例
     */
    @Bean
    Set<JsonNode> eventsQueue() {
        return new CopyOnWriteArraySet<>();
    }
}

在需要注入eventsQueue的类中,我使用Lombok的@AllArgsConstructor生成构造函数:

@Log4j2
@RestController
@AllArgsConstructor
public class EventsApiImpl implements EventsApi {

    private Set<JsonNode> eventsQueue;
    private MariaEventService mariaEventService;
    private EventManipulationService eventManipulationService;
    private ObjectMapper mapper;

    // 业务方法省略
}

但Spring启动时抛出如下错误:

Caused by: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean
with name 'EventsApiImpl': Unsatisfied dependency expressed through constructor parameter 0:
No qualifying bean of type 'java.util.Set[com.fasterxml.jackson.databind.JsonNode]' available: 
expected single matching bean but found 2: slowVarsQueue,eventsQueue

明明变量名和目标Bean的名称一致,为什么还是会报错?


原因分析

Spring构造函数注入的默认匹配逻辑是按类型匹配,而非参数名匹配。虽然你将字段名命名为eventsQueue,但Lombok生成的构造函数参数名在默认编译模式下会被丢失(编译后参数名会变成arg0、arg1这类占位符),导致Spring无法通过参数名识别要注入的目标Bean。此时Spring发现存在两个同类型的Set<JsonNode> Bean,无法确定选择哪一个,因此抛出冲突异常。


解决方法

1. 使用@Qualifier指定目标Bean

在字段上添加@Qualifier注解,明确指定要注入的Bean名称:

@Log4j2
@RestController
@AllArgsConstructor
public class EventsApiImpl implements EventsApi {

    @Qualifier("eventsQueue")
    private Set<JsonNode> eventsQueue;
    private MariaEventService mariaEventService;
    private EventManipulationService eventManipulationService;
    private ObjectMapper mapper;

    // 业务方法省略
}

2. 给目标Bean标记@Primary

如果大部分场景下都需要注入eventsQueue,可以在对应的@Bean方法上添加@Primary注解,让Spring在同类型Bean中优先选择它:

@Configuration
public class DataQueue {

    // 其他Bean定义省略

    @Bean
    @Primary
    Set<JsonNode> eventsQueue() {
        return new CopyOnWriteArraySet<>();
    }
}

3. 开启编译时保留参数名

在构建工具中配置编译选项,保留Java方法的参数名,让Spring能通过构造函数参数名匹配Bean名称:

Maven配置(pom.xml):

<build>
    <plugins>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-compiler-plugin</artifactId>
            <version>3.8.1</version>
            <configuration>
                <compilerArgs>
                    <arg>-parameters</arg>
                </compilerArgs>
            </configuration>
        </plugin>
    </plugins>
</build>

Gradle配置(build.gradle):

tasks.withType(JavaCompile) {
    options.compilerArgs << "-parameters"
}

配置后,编译生成的class文件会保留构造函数的参数名,Spring就能通过参数名eventsQueue自动匹配对应的Bean。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.23 05:17:10