关于dubbo-spring-boot-starter处理Multiple配置的疑问
问题简述
使用dubbo-spring-boot-starter
无法正确处理多 Dubbo 配置
,而原始dubbo
可以正确处理
多 Dubbo 配置 Bean 绑定
以下描述摘自Dubbo 外部化配置(Externalized Configuration)
Dubbo
@Service
和@Reference
允许 Dubbo 应用关联ApplicationConfig
Bean 或者指定多个RegistryConfig
Bean 等能力。换句话说,Dubbo 应用上下文中可能存在多个ApplicationConfig
等 Bean定义。
为了适应以上需要,因此从Dubbo2.5.9
开始,@EnableDubboConfig
支持多 Dubbo 配置 Bean 绑定,同时按照业界规约标准,与单 Dubbo 配置 Bean 绑定约定不同,配置属性前缀均为英文复数形式:
详情请参考 :https://github.com/alibaba/dubbo/issues/1141
- dubbo.applications
- dubbo.modules
- dubbo.registries
- dubbo.protocols
- dubbo.monitors
- dubbo.providers
- dubbo.consumers
使用使用官方https://github.com/apache/dubbo-spring-boot-project
提供的dubbo-spring-boot-starter
实践上述配置时会出现一些问题。而使用原始dubbo能正常处理。现描述如下,也请业界大佬帮忙解答是否为bug,亦或另有深意。
问题复现
maven配置
1. 原始dubbo依赖配置
<properties>
<spring-boot.version>2.1.6.RELEASE</spring-boot.version>
<dubbo.version>2.7.3</dubbo.version>
</properties>
...
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
<version>${spring-boot.version}</version>
</dependency>
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo</artifactId>
<version>${dubbo.version}</version>
</dependency>
2. 使用dubbo-spring-boot-starter依赖配置
<properties>
<spring-boot.version>2.1.6.RELEASE</spring-boot.version>
<dubbo.version>2.7.3</dubbo.version>
</properties>
...
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
<version>${spring-boot.version}</version>
</dependency>
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-spring-boot-starter</artifactId>
<version>${dubbo.version}</version>
</dependency>
第一个问题
使用dubbo-spring-boot-starter
处理如下配置
dubbo.consumers.user.application.name=consumers-user-application
dubbo.consumers.web.application.name=consumers-web-application
会报错:
Failed to bind properties under 'dubbo.consumers.web' to org.apache.dubbo.config.ConsumerConfig:
Reason: Duplicate Config found for ApplicationConfig, you should use only one unique ApplicationConfig for one application.
分析说明
原始dubbo与dubbo-spring-boot-starter处理dubbo.consumers.*
的异同代码说明
1. 原始dubbo使用org.apache.dubbo.config.spring.context.properties.DefaultDubboConfigBinder
处理配置绑定。而dubbo-spring-boot-starter使用org.apache.dubbo.spring.boot.autoconfigure.BinderDubboConfigBinder
。如下图:
- 原始dubbo
- dubbo-spring-boot-starter
2. 处理ConsumerConfig配置的异同
配置ConsumerConfig时会调用ConsumerConfig父类AbstractInterfaceConfig#setApplication方法配置ApplicationConfig。此时会使用org.apache.dubbo.config.context.ConfigManager#checkDuplicate
对Application配置做重复校验。
- 关键在此,原始dubbo方案配置ConsumerConfig时,对其私有ApplicationConfig只做了初始化而没有配置属性。所以处理以下配置时
dubbo.consumers.user.application.name=consumers-user-application
dubbo.consumers.web.application.name=consumers-web-application
根据org.apache.dubbo.config.context.ConfigManager#checkDuplicate
的处理逻辑始终都具有唯一性,从而正常校验通过。详细参考源码。
- 而使用dubbo-spring-boot-starter配置ConsumerConfig时,其私有的ApplicationConfig已完成了初始化和属性配置。所以当有多个
dubbo.consumers.*.application.*
配置时,org.apache.dubbo.config.context.ConfigManager#checkDuplicate
校验第二ConsumerConfig的ApplicationConfig时就会失败,从而报错。
以上说明的代码跟踪截图如下:
- 原始dubbo
第1次处理"dubbo.consumers.user.application.name=consumers-user-application",正常通过
第2次处理"dubbo.consumers.web.application.name=consumers-web-application",同样正常通过
- dubbo-spring-boot-starter
第1次处理"dubbo.consumers.user.application.name=consumers-user-application",正常通过,因为ConfigManager是单例调用,第一次调用时,内部属性application为null。
第2次处理"dubbo.consumers.web.application.name=consumers-web-application",失败报错。因为此时调用ConfigManager时,内部属性application保留了第一次调用时的application,且有完整的属性,所以调用checkDuplicate方法时报错。
其它类似dubbo.(*s).*.application.*
配置同样会包类似的错误
第二个问题
使用dubbo-spring-boot-starter
处理如下配置
dubbo.applications.app1.name=applications-app1
dubbo.applications.app2.name=applications-app1
会报错:
java.lang.IllegalStateException: There are more than one instances of ApplicationConfig, whose bean definitions : [Root bean: class [org.apache.dubbo.config.ApplicationConfig]; scope=; abstract=false; lazyInit=false; autowireMode=0; dependencyCheck=0; autowireCandidate=true; primary=false; factoryBeanName=null; factoryMethodName=null; initMethodName=null; destroyMethodName=null, Root bean: class [org.apache.dubbo.config.ApplicationConfig]; scope=; abstract=false; lazyInit=false; autowireMode=0; dependencyCheck=0; autowireCandidate=true; primary=false; factoryBeanName=null; factoryMethodName=null; initMethodName=null; destroyMethodName=null]
...
...
分析说明
dubbo-spring-boot-starter处理dubbo配置时,使用了org.apache.dubbo.spring.boot.beans.factory.config.DubboConfigBeanDefinitionConflictProcessor
类处理ApplicationConfig
配置冲突。
分析源码后,很费解其处理逻辑,根据逻辑,完全就排斥dubbo.applications.*
的配置。
代码跟踪截图如下:
第三个问题
org.apache.dubbo.config.AbstractConfig#equals
方法中为什么Exception情况下会返回true。
官方资料参考
关于多 Dubbo 配置 Bean 绑定,官方可参考的资源如下: