近期,项目微服务开始提供RPC服务,微服务之间改为dubbo调用。本地开发调试时,服务提供方和服务消费方都能正常启动,验证通过。
对于消费方,在bean的xml文件声明服务消费的引用方式:
<dubbo:reference id="operationWaybillService" interface="com.demo.service.OperationWaybillService" retries="0" timeout="6000" check="false" />
合入代码库并在测试环境部署,消费方无法启动,报错" Duplicate spring bean id
很明显,提示bean重复注册了。但是为什么本地环境是OK的,但测试环境却有问题?
结合网上搜索到的方法,一一尝试:
1. 在xml配置文件中重复声明同一个bean
经排查,并没有。
2. bean的id跟项目中其他方法重名了,包括pom引用其他模块时有相同的bean id值,需要修改id的名字
排查了其他模块,没有同名的service方法。另外把bean的id值修改成奇奇怪怪的值,还是无效。
3. 既然本地(1台应用)运行正常,测试环境(2台应用)不行,那环境有差别
把测试环境的1台应用停掉,只启用1台,还是不行。
4. 把本地jar包拷贝到测试环境上,有效!
后来发现这是歪打正着,因为本地代码与测试环境代码不是同一套,本地bean的id与测试环境bean的id不一样,当然不会重复注册了。
(注:定位问题时,一定要确保代码是同一套)
最后解决方法:
由于是bean被两次注册,且本地成功,测试环境失败,联想到测试环境部署的conf目录下也存在一份META-INF,怀疑是它导致的。
META-INF下也有同样的spring配置文件,导致会重复注册两次。
故修改assembly.xml文件中的配置,打包时排除掉META-INF下的文件
进一步分析:
在Dubbo源码中,当ref的required为true时,会有个while循环控制bean的id保证唯一,如下图:
当bean没有设置id值,且required=true时,会将bean的name属性值或者bean的类名作为id值。当ParserContext上下文有该id的注册信息时,会循环对id值进行加1赋值,直到id值是唯一的。
最后从ParserContext的注册上下文中判断id值是否冲突,有则抛出异常“Duplicate spring bean id”。