Spring Boot 3.2.3升级后WebFlux出现Config Bean重复定义问题求助
Spring Boot 3.2.3升级后WebFlux多模块应用出现重复Config Bean问题
问题背景
将Spring Boot版本从3.1.6升级到3.2.3后,原有正常运行的WebFlux多模块应用启动失败,应用结构如下:
- config模块:包含读取
application.properties配置的Config.java - webservice模块:包含
Controller.java,依赖config模块 - compute模块:包含
Compare.java和ClientAPI.java,依赖config模块
启动错误信息
14:57:56.453 INFO m.ClientConfig - WebClient Creation init 14:57:56.668 WARN o.s.b.w.r.c.AnnotationConfigReactiveWebServerApplicationContext - Exception encountered during context initialization - cancelling refresh attempt: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'controller': Unsatisfied dependency expressed through field 'compare': Error creating bean with name 'compare': Unsatisfied dependency expressed through field 'clientAPI': Error creating bean with name 'clientAPI' defined in file [C:\git\project\compute\target\classes\mypackage\service\ClientAPI.class]: Unsatisfied dependency expressed through constructor parameter 1: No qualifying bean of type 'mypackage.config.Config' available: expected single matching bean but found 2: config,mypackage.config.Config 14:57:56.698 INFO o.s.b.a.l.ConditionEvaluationReportLogger - Error starting ApplicationContext. To display the condition evaluation report re-run your application with 'debug' enabled. 14:57:56.731 ERROR o.s.b.d.LoggingFailureAnalysisReporter - *************************** APPLICATION FAILED TO START *************************** Description: Parameter 1 of constructor in mypackage.service.ClientAPI required a single bean, but 2 were found: - config: defined in file [C:\git\project\config\target\classes\mypackage\config\Config.class] - mypackage.config.Config: defined in unknown location This may be due to missing parameter name information Action: Consider marking one of the beans as @Primary, updating the consumer to accept multiple beans, or using @Qualifier to identify the bean that should be consumed
相关代码片段
Controller.java
import mypackage.service.Compare; import mypackage.config.Config; @RestController @RequestMapping("/v1") public class Controller { @Autowired Compare compare; @Autowired Config config; private static final String COMPARE_PATH_SERVICE = "/compare"; @PostMapping(path = COMPARE_PATH_SERVICE, consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE) public Mono<Response> getResponse(@RequestHeader("requestId") String requestId, @RequestBody @Valid InputData inputData) { if (config.getMyPersonalKey().equalsIgnoreCase("value")){ return compare.compute(requestId, inputData); } else { // 省略其他逻辑 } } }
Compare.java
package mypackage.service; import mypackage.config.Config; @Service public class Compare { @Autowired ClientAPI clientAPI; @Autowired Config config; public Mono<Response> compute(String requestId,@Valid InputData inputData) { return clientAPI.sendRequest(requestManagement.buildRequest(requestId, inputData)) .flatMap(response -> { // 省略其他逻辑 return Mono.just(response); }); } }
ClientAPI.java
(注:下方引用的WebClient由其他模块通过"MyWebClient"限定符创建)
package mypackage.service; import mypackage.config.Config; @Service public class ClientAPI { private WebClient webClient; private static final String URI = "/subsystem/v1/compare"; private String url; @Autowired public ClientAPI(@Qualifier("WebClient") WebClient webClient, Config config) { this.url = "https://" + config.getServiceHost() + ":" + config.getServicePort() + URI; this.webClient = webClient; } public Mono<Response> sendRequest(Request bodyRequest) { return this.webClient.post().uri(this.url) .header(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE) .body(Mono.just(bodyRequest), Request.class).retrieve().bodyToMono(Response.class); } }
Config.java
package mypackage.config; @ConfigurationProperties @Component //@Primary // 取消注释后应用可正常运行 public class Config { @Value("${my.personal.key}") String myPersonalKey; public String getMyPersonalKey() { return myPersonalKey; } }
已尝试的解决方法
给Config.java添加@Primary注解后,应用可正常启动,但不清楚为何会出现两个Config Bean实例。
问题原因分析
你的Config类同时使用了@Component和@ConfigurationProperties注解,这在Spring Boot 3.2版本中触发了重复Bean注册的问题:
- 第一次注册:
@Component注解会被Spring的组件扫描机制识别,将Config类注册为名为config的Bean(对应错误日志中来自config模块类文件的实例)。 - 第二次注册:Spring Boot 3.2对
@ConfigurationProperties的处理逻辑进行了调整——即使类上已经存在@Component,配置属性绑定机制仍会自动将该类注册为一个独立的Bean,名称为类的全限定名mypackage.config.Config(对应错误日志中"未知位置"的实例)。 - 多模块场景下,各个模块的组件扫描范围覆盖到了
Config类,进一步触发了这两次注册逻辑,最终导致容器中存在两个同类型的Bean,注入时出现冲突。
优化解决方法
不推荐仅依赖@Primary注解绕过问题,建议统一配置属性类的注册方式:
方法一:移除@Component,使用配置属性扫描
- 从
Config.java中移除@Component注解,仅保留@ConfigurationProperties:
package mypackage.config; @ConfigurationProperties public class Config { @Value("${my.personal.key}") String myPersonalKey; public String getMyPersonalKey() { return myPersonalKey; } }
- 在应用的主启动类上添加
@ConfigurationPropertiesScan注解,指定扫描mypackage.config包:
@SpringBootApplication @ConfigurationPropertiesScan(basePackages = "mypackage.config") public class Application { public static void main(String[] args) { SpringApplication.run(Application.class, args); } }
方法二:保留@Component,禁用自动注册配置属性Bean
如果需要保留@Component,可以通过配置关闭@ConfigurationProperties的自动注册:
在application.properties中添加:
spring.boot.configurations.auto-registration.enabled=false
不过这种方法不推荐,因为会影响其他配置属性类的自动处理。
内容的提问来源于stack exchange,提问作者cknelle
相关产品推荐
相关产品推荐

