springboot+dubbo启动失败Duplicate spring bean id

版权声明:本文为博主原创文章,转载请注明出处。 https://blog.csdn.net/u010597819/article/details/90717117

dubbo版本:2.6.5,springboot版本:1.5.17

问题描述

最近公司要将dubbo改为api配置方式,由于xml配置很多过渡期会混合使用两种配置。升级改造期间服务竟然报错重复bean id异常,异常堆栈如下

2019-05-31 09:43:00,620 ERROR [main] org.springframework.boot.SpringApplication::  Application startup failed
org.springframework.beans.factory.BeanDefinitionStoreException: Unexpected exception parsing XML document from file [D:\git\...\dispatch\dispatch-monitor-task\dispatch-monitor-task-server\target\classes\spring\dubbo-consumer.xml]; nested exception is java.lang.IllegalStateException: Duplicate spring bean id cityQueryProvider
	at org.springframework.beans.factory.xml.XmlBeanDefinitionReader.doLoadBeanDefinitions(XmlBeanDefinitionReader.java:414) ~[spring-beans-4.3.20.RELEASE.jar:4.3.20.RELEASE]
	at org.springframework.beans.factory.xml.XmlBeanDefinitionReader.loadBeanDefinitions(XmlBeanDefinitionReader.java:336) ~[spring-beans-4.3.20.RELEASE.jar:4.3.20.RELEASE]
	at org.springframework.beans.factory.xml.XmlBeanDefinitionReader.loadBeanDefinitions(XmlBeanDefinitionReader.java:304) ~[spring-beans-4.3.20.RELEASE.jar:4.3.20.RELEASE]
	at org.springframework.beans.factory.support.AbstractBeanDefinitionReader.loadBeanDefinitions(AbstractBeanDefinitionReader.java:181) ~[spring-beans-4.3.20.RELEASE.jar:4.3.20.RELEASE]
	at org.springframework.beans.factory.support.AbstractBeanDefinitionReader.loadBeanDefinitions(AbstractBeanDefinitionReader.java:217) ~[spring-beans-4.3.20.RELEASE.jar:4.3.20.RELEASE]
	at org.springframework.beans.factory.support.AbstractBeanDefinitionReader.loadBeanDefinitions(AbstractBeanDefinitionReader.java:188) ~[spring-beans-4.3.20.RELEASE.jar:4.3.20.RELEASE]
	at org.springframework.context.annotation.ConfigurationClassBeanDefinitionReader.loadBeanDefinitionsFromImportedResources(ConfigurationClassBeanDefinitionReader.java:354) ~[spring-context-4.3.20.RELEASE.jar:4.3.20.RELEASE]
	at org.springframework.context.annotation.ConfigurationClassBeanDefinitionReader.loadBeanDefinitionsForConfigurationClass(ConfigurationClassBeanDefinitionReader.java:143) ~[spring-context-4.3.20.RELEASE.jar:4.3.20.RELEASE]
	at org.springframework.context.annotation.ConfigurationClassBeanDefinitionReader.loadBeanDefinitions(ConfigurationClassBeanDefinitionReader.java:116) ~[spring-context-4.3.20.RELEASE.jar:4.3.20.RELEASE]
	at org.springframework.context.annotation.ConfigurationClassPostProcessor.processConfigBeanDefinitions(ConfigurationClassPostProcessor.java:320) ~[spring-context-4.3.20.RELEASE.jar:4.3.20.RELEASE]
	at org.springframework.context.annotation.ConfigurationClassPostProcessor.postProcessBeanDefinitionRegistry(ConfigurationClassPostProcessor.java:228) ~[spring-context-4.3.20.RELEASE.jar:4.3.20.RELEASE]
	at org.springframework.context.support.PostProcessorRegistrationDelegate.invokeBeanDefinitionRegistryPostProcessors(PostProcessorRegistrationDelegate.java:272) ~[spring-context-4.3.20.RELEASE.jar:4.3.20.RELEASE]
	at org.springframework.context.support.PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(PostProcessorRegistrationDelegate.java:92) ~[spring-context-4.3.20.RELEASE.jar:4.3.20.RELEASE]
	at org.springframework.context.support.AbstractApplicationContext.invokeBeanFactoryPostProcessors(AbstractApplicationContext.java:687) ~[spring-context-4.3.20.RELEASE.jar:4.3.20.RELEASE]
	at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:525) ~[spring-context-4.3.20.RELEASE.jar:4.3.20.RELEASE]
	at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:693) ~[spring-boot-1.5.17.RELEASE.jar:1.5.17.RELEASE]
	at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:360) ~[spring-boot-1.5.17.RELEASE.jar:1.5.17.RELEASE]
	at org.springframework.boot.SpringApplication.run(SpringApplication.java:303) ~[spring-boot-1.5.17.RELEASE.jar:1.5.17.RELEASE]
	at org.springframework.boot.SpringApplication.run(SpringApplication.java:1118) ~[spring-boot-1.5.17.RELEASE.jar:1.5.17.RELEASE]
	at org.springframework.boot.SpringApplication.run(SpringApplication.java:1107) ~[spring-boot-1.5.17.RELEASE.jar:1.5.17.RELEASE]
	at com.....dispatch.monitor.Application.main(Application.java:20) ~[classes/:?]
Caused by: java.lang.IllegalStateException: Duplicate spring bean id cityQueryProvider
	at com.alibaba.dubbo.config.spring.schema.DubboBeanDefinitionParser.parse(DubboBeanDefinitionParser.java:100) ~[dubbo-2.6.5-wireless-1.jar:2.6.5-wireless-1]
	at com.alibaba.dubbo.config.spring.schema.DubboBeanDefinitionParser.parse(DubboBeanDefinitionParser.java:417) ~[dubbo-2.6.5-wireless-1.jar:2.6.5-wireless-1]
	at org.springframework.beans.factory.xml.NamespaceHandlerSupport.parse(NamespaceHandlerSupport.java:74) ~[spring-beans-4.3.20.RELEASE.jar:4.3.20.RELEASE]
	at org.springframework.beans.factory.xml.BeanDefinitionParserDelegate.parseCustomElement(BeanDefinitionParserDelegate.java:1410) ~[spring-beans-4.3.20.RELEASE.jar:4.3.20.RELEASE]
	at org.springframework.beans.factory.xml.BeanDefinitionParserDelegate.parseCustomElement(BeanDefinitionParserDelegate.java:1400) ~[spring-beans-4.3.20.RELEASE.jar:4.3.20.RELEASE]
	at org.springframework.beans.factory.xml.DefaultBeanDefinitionDocumentReader.parseBeanDefinitions(DefaultBeanDefinitionDocumentReader.java:172) ~[spring-beans-4.3.20.RELEASE.jar:4.3.20.RELEASE]
	at org.springframework.beans.factory.xml.DefaultBeanDefinitionDocumentReader.doRegisterBeanDefinitions(DefaultBeanDefinitionDocumentReader.java:142) ~[spring-beans-4.3.20.RELEASE.jar:4.3.20.RELEASE]
	at org.springframework.beans.factory.xml.DefaultBeanDefinitionDocumentReader.registerBeanDefinitions(DefaultBeanDefinitionDocumentReader.java:94) ~[spring-beans-4.3.20.RELEASE.jar:4.3.20.RELEASE]
	at org.springframework.beans.factory.xml.XmlBeanDefinitionReader.registerBeanDefinitions(XmlBeanDefinitionReader.java:508) ~[spring-beans-4.3.20.RELEASE.jar:4.3.20.RELEASE]
	at org.springframework.beans.factory.xml.XmlBeanDefinitionReader.doLoadBeanDefinitions(XmlBeanDefinitionReader.java:392) ~[spring-beans-4.3.20.RELEASE.jar:4.3.20.RELEASE]
	... 20 more

问题分析

配置问题?

起初最先想到是配置问题当然idea直接包含jar包一起搜索该bean的配置使用类,结果并没有重复配置改bean的声明,所以不是配置问题

什么原因导致的重复注册?

  1. 异常堆栈中可以看到是xml解析向工厂注册bean定义时抛出的异常
  2. 那么是不是重复解析了呢?于是我们断点跟踪DubboNamespaceHandler,发现确实初始化了两次该实例
  3. 那么问题基本定位了,两次重复的初始化导致每个元素(例如:application)的DubboBeanDefinitionParser重复注册两个相同的解析器解析,那么就会出现我们上面所看到的异常

为什么DubboNamespaceHandler会重复初始化两次?

  1. 从解析配置中我们看到目前是有两个不同的命名空间使用了同一个DubboNamespaceHandler句柄,那么会不会是因为项目中同时使用了两种命名空间导致的呢?
spring.handlers
http\://dubbo.apache.org/schema/dubbo=com.alibaba.dubbo.config.spring.schema.DubboNamespaceHandler
http\://code.alibabatech.com/schema/dubbo=com.alibaba.dubbo.config.spring.schema.DubboNamespaceHandler
-----------------
spring.schemas
http\://dubbo.apache.org/schema/dubbo/dubbo.xsd=META-INF/dubbo.xsd
http\://code.alibabatech.com/schema/dubbo/dubbo.xsd=META-INF/compat/dubbo.xsd
  1. 检查项目中配置,并木有,并且我们断点查看初始化的位置DefaultNamespaceHandlerResolver.resolve两次初始化的namespaceUri都是同一个,啊啊啊,土拨鼠版嚎叫
  2. 但是在我们debug期间观察发现DefaultNamespaceHandlerResolver实例是两个不同的实例,也就是DefaultNamespaceHandlerResolver也被实例化了两次,对同一个namespaceUri执行了两次解析resolve
  3. 查找该解析的调用者
  4. image.png
  5. 可以看到BeanDefinitionParserDelegate的两次调用使用的是同一个实例,父类的namespaceHandlerResolver,并且仅能在XmlReaderContext构造器中注入,断点可以看到BeanDefinitionParserDelegate与readerContext实例也不是同一个
  6. 我们跟着堆栈从springboot应用启动开始逐步定位重复注册bean的点
  7. ConfigurationClassBeanDefinitionReader加载bean定义(loadBeanDefinitions)时便出现了重复注册bean问题跟着代码我们定位到是在加载我们内部自动配置类中的DubboAutoConfiguration的定义时产生的
  8. 查看DubboAutoConfiguration自动配置类发现指定的ImportResource为spring/*目录配置,也就是consumer、provider配置的xml所在目录,此时读取导入BeanDefinition是正常流程,但是之前已经加载过一次,这次再次去加载便出现开始所描述的异常
@Configuration
@ImportResource(
    locations = {"classpath:spring/*"}
)
public class DubboAutoConfiguration {
    ...
}
--------- 重复配置导致
@Configuration
@ImportResource(locations = {"classpath:spring/*", "classpath*:spring/disconf.xml"})
public class AppConfig {
	...
}

问题解决

问题定位后,解决方法自然也就清楚了,第一次加载的原因是因为应用的AppConfig中指定了classpath:spring/*配置。第二次加载是因为DubboAutoConfiguration配置中也指定了classpath:spring/*配置,所以只要删除其中一个即可

问题总结

  1. 一个bean虽然今配置了一次,但是如果Configuration配置中指定xml目录重复,导致对xml中定义的bean重复扫描加载,产生了bean定义的重复冲突问题
  2. 如果发现bean的id重复
  3. 首先查找是否存在重复的id声明。
  4. 其次检查配置是否有重复Configuration导入配置
  5. 最后如果依然没发现则可以从ConfigurationClassBeanDefinitionReader加载bean定义(loadBeanDefinitions)的地方断点检查究竟是哪个配置引起的重复bean定义(例如:抛出异常时在导入哪个Configuration配置类)

猜你喜欢

转载自blog.csdn.net/u010597819/article/details/90717117