一、概述
在项目开发中,由于多个 FeignClient
使用了相同的 name
,导致SpringBoot启动时出现 BeanDefinitionOverrideException
异常。
解决方案是在每个 FeignClient
上添加唯一的 contextId
,如 userFeignClient
和 helloWorldFeignClient
,以避免bean名称冲突。
二、场景分析
通过 OpenFeign 调用远程服务的接口,远程服务的接口按照业务逻辑,划分为不同的模块。如果远程服务是SpringBoot项目的话,表现形式就是接口按照业务逻辑划分到不同的控制器Controller。
在客户端服务中,使用 FeignClient 来定义一组接口。一个 FeignClient 对应一个远程服务的控制器Controller,FeignClient 中的接口和远程服务的控制器方法对应。
OpenFeign 在访问远程服务时,多个 FeignClient 都访问同一个服务,只不过这个服务有多组接口(也就是有多个控制器Controller)。此时,多个 FeignClient 的 name
字段是相同的,导致 SpringBoot 启动报错,抛出 BeanDefinitionOverrideException
异常。
- 用户管理相关接口:
@FeignClient(name = "hello-world", url = "${hello-world.url}", path = "/users")
public interface UserFeignClient {
@GetMapping("/{id}")
UserVo getUserById(@PathVariable String id);
}
- 其他服务相关接口:
@FeignClient(name = "hello-world", url = "${hello-world.url}", path = "/hello")
public interface HelloWorldFeignClient {
@GetMapping
String hello();
}
三、启动报错
2024-08-25T16:50:51.288+08:00 WARN 5372 --- [hello-feign-client] [ main] ConfigServletWebServerApplicationContext : Exception encountered during context initialization - cancelling refresh attempt: org.springframework.beans.factory.support.BeanDefinitionOverrideException: Invalid bean definition with name 'hello-world.FeignClientSpecification' defined in null: Cannot register bean definition [Generic bean: class [org.springframework.cloud.openfeign.FeignClientSpecification]; scope=; abstract=false; lazyInit=null; autowireMode=0; dependencyCheck=0; autowireCandidate=true; primary=false; factoryBeanName=null; factoryMethodName=null; initMethodNames=null; destroyMethodNames=null] for bean 'hello-world.FeignClientSpecification' since there is already [Generic bean: class [org.springframework.cloud.openfeign.FeignClientSpecification]; scope=; abstract=false; lazyInit=null; autowireMode=0; dependencyCheck=0; autowireCandidate=true; primary=false; factoryBeanName=null; factoryMethodName=null; initMethodNames=null; destroyMethodNames=null] bound.
2024-08-25T16:50:51.306+08:00 INFO 5372 --- [hello-feign-client] [ main] .s.b.a.l.ConditionEvaluationReportLogger :
Error starting ApplicationContext. To display the condition evaluation report re-run your application with 'debug' enabled.
2024-08-25T16:50:51.389+08:00 ERROR 5372 --- [hello-feign-client] [ main] o.s.b.d.LoggingFailureAnalysisReporter :
***************************
APPLICATION FAILED TO START
***************************
Description:
The bean 'hello-world.FeignClientSpecification' could not be registered. A bean with that name has already been defined and overriding is disabled.
Action:
Consider renaming one of the beans or enabling overriding by setting spring.main.allow-bean-definition-overriding=true
- 报错说明如下:
The bean ‘hello-world.FeignClientSpecification’ could not be registered. A bean with that name has already been defined and overriding is disabled.
无法注册Bean“hello-world.FeignClientSpecification”。已经定义了具有该名称的bean,并且禁用了重写。
四、解决方案
使用 contextId
区分同一个服务的不同 FeignClient 。
当 contextId 不为空时,直接就用 contextId 作为 bean 的名称;当 contextId 为空时,才会使用 value/name 作为bean名称.
- 用户管理相关接口:
@FeignClient(contextId = "userFeignClient", name = "hello-world", url = "${hello-world.url}", path = "/users")
public interface UserFeignClient {
@GetMapping("/{id}")
UserVo getUserById(@PathVariable String id);
}
- 其他服务相关接口:
@FeignClient(contextId = "helloWorldFeignClient", name = "hello-world", url = "${hello-world.url}", path = "/hello")
public interface HelloWorldFeignClient {
@GetMapping
String hello();
}
五、官方文档
六、参考文章
两个FeignClient接口使用相同服务名报错问题