apache / dubbo-spring-boot-project

Spring Boot Project for Apache Dubbo
https://dubbo.apache.org
Apache License 2.0
5.41k stars 1.88k forks source link

application.properties与dubbo.xml配置的兼容性问题 #746

Open furaul opened 4 years ago

furaul commented 4 years ago

问题描述:

application.properties与dubbo.xml配置的兼容性问题。 dubbo.xml中reference或者service配置会影响application.properties中的config-center配置读取。

依赖版本:

基于dubbo-spring-boot-project 2.7.6 - 2.7.8 均存在该问题。

重现步骤:

在application.properties中做配置中心相关配置,配置内容如下:

dubbo.config-center.address=localhost:80
apollo.meta=localhost:80
dubbo.config-center.protocol=apollo
dubbo.config-center.namespace=arch.namespace
dubbo.config-center.parameters.config.namespace=arch.namespace
dubbo.config-center.parameters.config.group=arch.group
dubbo.config-center.cluster=qa
app.id=consumer-demo

在dubbo.xml中配置ReferenceBean,配置内容如下:

<dubbo:reference interface="org.apache.dubbo.spring.boot.sample.consumer.DemoService" id="demo1" lazy="true"/>

在springboot启动类中引入xml配置。

预期结果:

配置中心的配置内容(如namespace等)可以在ApolloDynamicConfiguration初始化的时候被读取到。 expect

实际结果:

ApolloDynamicConfiguration在初始化的时候,参数url中的和配置中心相关的内容都是默认值,比如namespace=dubbo。 real

如果去掉xml中的 dubbo:reference声明,或者使用基于注解的Reference声明,都能得到预期的结果。

初步分析:

当前初步确认,直接原因是xml中的bean引发的加载时机问题,当xml中声明dubbo:reference或者dubbo:service,会导致更早的实例化,然后org.apache.dubbo.config.bootstrap.DubboBootstrap#startConfigCenter中发现configManager的实例中并没有事先加载的ConfigCenterConfig的实例,进入if逻辑再次重新加载的时候就会生成一个全部使用默认值的实例。

请教有没有比较好的解决方案。

代码示例

https://github.com/furaul/dubbo-spring-boot-project 的 master分支 使用org.apache.dubbo.spring.boot.sample.provider.bootstrap.DubboAutoConfigurationProviderBootstrap 启动示例。

pkxiuluo commented 4 years ago

遇见同样问题,似乎 application.properties 与xml方式完全不能兼容。

furaul commented 4 years ago

@mercyblitz

kylixs commented 3 years ago

跟踪一下初始化过程,发现问题在于serviceClassPostProcessor的初始化导致意外提前初始化ReferenceBean,接着初始化ConfigCenterBean,导致application.properties配置的dubbo.config-center没有起效。

初始化DubboAutoConfiguration.serviceClassPostProcessor() -> 查找参数bean: Set packagesToScan -> getBeanNamesForType(String) -> ReferenceBean (FactoryBean, allowEagerInit) -> isTypeMatch -> getTypeForFactoryBean -> createBean (ReferenceBean) -> ReferenceBean.prepareDubboConfigBeans -> beansOfTypeIncludingAncestors(ConfigCenterBean) -> init ConfigCenterBean -> serviceClassPostProcessor 为BeanFactoryPostProcessor,此时CommonAnnotationBeanPostProcessor 未加载,没有调用@PostContruct addIntoConfigManager()