@EnableFeignClients
注解配置导致重复加载问题;
The bean ‘xxx.FeignClientSpecification’, defined in null, could not be registered. A bean with that name has already been defined in null and overriding is disabled.
1. 项目背景
可以将SDK看做是
apache commons
工具jar包,AVA项目加载SDK,获得处理特定业务的能力。
1.1. SDK(寄生项目)
1 | SpringBoot搭建 |
1.2. AVA项目(宿主项目)
1 | 标准SpringBoot项目 |
2. 项目环境描述
这两个项目不是新项目,在两个月前,就通过联调测试,并且发布到了预生产环境。此后SDK并没有再修改上传代码。
最近增加了新的需求后,开发人员将AVA项目重新构建依赖后,进行本地开发,发现AVA项目无法启动。
3. 异常描述
3.1. 异常表现
1 | SpringBoot 项目启动失败 |
3.2. 异常信息
1 | Description: |
4. 异常分析
虽然第一反应知道肯定不是SDK的问题(因为两个月没有提交代码了),本着负责任的态度,还是先从自身项目查起。
5. 排查
看到异常的第一反应是 @FeignClient
的名称重复了?
网上查了下,大部分的定位思路也是:FeignClient注解使用的服务名重复
解决方案是以下三种:
排查重复的
@FeignClient
名称,同一个服务的接口,不要分散的写在多个接口类中在
@FeignClient
中添加contextId
属性,通过添加命名空间属性解决。开启
spring.main.allow-bean-definition-overriding: true
配置。
SpringCloud 2.1.0 以上版本,不再默认支持 FeignClient 的name属性 的相同名字。
即多个接口上的@FeignClient(“service-name”)会报错,overriding is disabled(覆盖是禁止的)。该配置允许 FeignClient 的名称重复.
排查以后SDK中并没有找到重复的 Feign
,AVA项目也没有使用 Feign
功能。
有些郁闷,没有重复的名称,为啥会有这个异常呢?于是重新看了下异常信息,目光落在"xxx.service.FeignClientSpecification"上。
FeignClientSpecification
这个类是 spring openfeign 中的源码类,为什么会说它无法注册呢?
突然想到,SDK项目是以jar形式,提供给AVA项目进行加载的,会不会是我的jar包被重复扫描了?
找到AVA开发人员,要来代码阅读权限,拉取代码,构建相关依赖,然后开始扒它依赖的jar包。
排除掉那些 spring、apache 等的jar包,范围缩小到该组开发人员自己封装的工具jar包。
打开以后,一个个包看过去,好家伙,终于找到问题所在。
SDK中的自动配置类
1
2
3
4
5
6
7
public class CrmClientAutoConfigure {
}@EnableFeignClients
注解会扫描指定路径下,所有使用注解@FeignClient
定义的feign客户端。SDK中指定扫描的包路径是:“com.paxxx.crm.client”
AVA项目,该组开发人员自己封装的工具jar包
xxx-cloud-client.jar,看下源码
1
2
3
4
5
6
7
8
public class XXXFeignAutoConfigure {工具包指定扫描包路径:“com.paxxx”
@EnableFeignClients
扫描的包路径重复了。
6. 小结
自此,问题根源找到了,多个@EnableFeignClients
注解,扫描同一包路径(包路径覆盖),导致 feign客户端 被重复加载。
7. 思考
从项目、工程、应用角度看,SDK中的代码是没有问题的。
虽然最后还是我被迫做了调整。
反观AVA项目中自己封装的工具包,将@EnableFeignClients
放在工具包中,感觉实在不妥。
即便是放置在工具包中,也应该提供开关、配置,对重复、覆盖的包路径进行妥善处理。