Dubbo |ˈdʌbəʊ| 分布式初体验 —— 第二章 Dubbo 使用配置
1. Dubbo 配置方式及优先级
1.1. 配置方式
从Dubbo支持的配置来源说起,默认有6种配置来源:
- JVM System Properties,JVM -D 参数
- System environment,JVM进程的环境变量
- Externalized Configuration,外部化配置,从配置中心读取
- Application Configuration,应用的属性配置,从 Spring 应用的 Environment 中提取
dubbo
打头的属性集 - API / XML / 注解等编程接口采集的配置可以被理解成配置来源的一种,是直接面向用户编程的配置采集方式
- 从 Classpath 读取配置文件
dubbo.properties
1.2. 覆盖关系:
下图展示了 Dubbo 配置覆盖关系的优先级,从上到下优先级依次降低:

1.3. 配置加载流程
1.4. 一些常用的配置
XML 详细配置参考:https://dubbo.apache.org/zh/docs/references/xml/
标签 | 用途 | 解释 |
---|---|---|
<dubbo:service/> |
服务配置 | 用于暴露一个服务,定义服务的元信息,一个服务可以用多个协议暴露,一个服务也可以注册到多个注册中心 |
<dubbo:reference/> |
引用配置 | 用于创建一个远程服务代理,一个引用可以指向多个注册中心 |
<dubbo:protocol/> |
协议配置 | 用于配置提供服务的协议信息,协议由提供方指定,消费方被动接受 |
<dubbo:application/> |
应用配置 | 用于配置当前应用信息,不管该应用是提供者还是消费者 |
<dubbo:module/> |
模块配置 | 用于配置当前模块信息,可选 |
<dubbo:registry/> |
注册中心配置 | 用于配置连接注册中心相关信息 |
<dubbo:monitor/> |
监控中心配置 | 用于配置连接监控中心相关信息,可选 |
<dubbo:provider/> |
提供方配置 | 当 ProtocolConfig 和 ServiceConfig 某属性没有配置时,采用此缺省值,可选 |
<dubbo:consumer/> |
消费方配置 | 当 ReferenceConfig 某属性没有配置时,采用此缺省值,可选 |
<dubbo:method/> |
方法配置 | 用于 ServiceConfig 和 ReferenceConfig 指定方法级的配置信息 |
<dubbo:argument/> |
参数配置 | 用于指定方法参数配置 |
1.5. 配置之间的关系
1.6. 不同粒度配置的覆盖关系
以 timeout 为例,下图显示了配置的查找顺序,其它 retries, loadbalance, actives 等类似:
- 方法级优先,接口级次之,全局配置再次之。
- 如果级别一样,则消费方优先,提供方次之。
其中,服务提供方配置,通过 URL 经由注册中心传递给消费方。

2. dubbo.properties
Dubbo 属性配置有两个职责:
- 定义配置:根据属性创建配置组件实例,类似 SpringBoot 的
@ConfigurationProperties
的作用。 - 属性覆盖:覆盖已存在的配置组件实例的属性值,类似 Spring
PropertyOverrideConfigurer
的作用。
关于 dubbo.properties
属性:
- 如果在 Classpath 下有超过一个
dubbo.properties
文件,比如,两个 Jar 包都各自包含了dubbo.properties
,dubbo 将随机选择一个加载,并且打印错误日志。 - Dubbo 可以自动加载 Classpath 根目录下的
dubbo.properties
,但是你同样可以使用 JVM 参数来指定路径:-Ddubbo.properties.file=xxx.properties
。
2.1. 映射规则
将 XML 配置的标签名 + 属性名,用点分隔,多个拆成多行,例如:
dubbo.application.name=foo
等价于<dubbo:application name="foo" />
dubbo.registry.address=10.20.153.10:9090
等价于<dubbo:registry address="10.20.153.10:9090" />
如果 XML 有多行同名标签配置,可以用 ID 号区分,如果没有 ID 号则将所有同名标签生效,例如
dubbo.protocol.rmi.port=1234
等价于<dubbo:protocol id="rmi" name="rmi" port="1099" />
dubbo.registry.china.address=10.20.153.10:9090
等价于<dubbo:registry id="china" address="10.20.153.10:9090" />
下面的 dubbo.properties
的一个典型配置:
dubbo.application.name=foo
dubbo.application.owner=bar
dubbo.registry.address=10.20.153.10:9090
2.2. 覆盖关系
下图展示了配置覆盖关系的优先级,从上到下优先级依次降低:

2.3. 属性覆盖
属性覆盖是指用配置的属性值覆盖 Config Bean实例的属性,类似 Spring PropertyOverrideConfigurer 的作用。
Property resource configurer that overrides bean property values in an application context definition. It pushes values from a properties file into bean definitions. Configuration lines are expected to be of the following form:
beanName.property=value
但与 PropertyOverrideConfigurer
的不同之处是,Dubbo 的属性覆盖有多个匹配格式,优先级从高到低依次是:
#1. 指定id的实例级配置
dubbo.{config-type}s.{config-id}.{config-item}={config-item-value}
#2. 指定name的实例级配置
dubbo.{config-type}s.{config-name}.{config-item}={config-item-value}
#3. 应用级配置(单数配置)
dubbo.{config-type}.{config-item}={config-item-value}
属性覆盖处理流程:
按照优先级从高到低依次查找,如果找到此前缀开头的属性,则选定使用这个前缀提取属性,忽略后面的配置。
2.4. 单复数配置对照表
复数配置的命名与普通单词变复数的规则相同:
- 辅音字母 +
y
结尾时,去掉y
,改为ies
- 字母
s
、sh
、ch
结尾时,加es
- 其它加
s
Config Type | 单数配置 | 复数配置 |
---|---|---|
application | dubbo.application.xxx=xxx |
dubbo.applications.{id}.xxx=xxx dubbo.applications.{name}.xxx=xxx |
protocol | dubbo.protocol.xxx=xxx |
dubbo.protocols.{id}.xxx=xxx dubbo.protocols.{name}.xxx=xxx |
module | dubbo.module.xxx=xxx |
dubbo.modules.{id}.xxx=xxx dubbo.modules.{name}.xxx=xxx |
registry | dubbo.registry.xxx=xxx |
dubbo.registries.{id}.xxx=xxx |
monitor | dubbo.monitor.xxx=xxx |
dubbo.monitors.{id}.xxx=xxx |
config-center | dubbo.config-center.xxx=xxx |
dubbo.config-centers.{id}.xxx=xxx |
metadata-report | dubbo.metadata-report.xxx=xxx |
dubbo.metadata-reports.{id}.xxx=xxx |
ssl | dubbo.ssl.xxx=xxx |
dubbo.ssls.{id}.xxx=xxx |
metrics | dubbo.metrics.xxx=xxx |
dubbo.metricses.{id}.xxx=xxx |
provider | dubbo.provider.xxx=xxx |
dubbo.providers.{id}.xxx=xxx |
consumer | dubbo.consumer.xxx=xxx |
dubbo.consumers.{id}.xxx=xxx |
service | dubbo.service.{interfaceName}.xxx=xxx |
无 |
reference | dubbo.reference.{interfaceName}.xxx=xxx |
无 |
method | dubbo.service.{interfaceName}.{methodName}.xxx=xxx dubbo.reference.{interfaceName}.{methodName}.xxx=xxx |
无 |
argument | dubbo.service.{interfaceName}.{methodName}.{arg-index}.xxx=xxx |
无 |
3. 启动时检查
启动时检查可以在启动时检查依赖的服务是否可用
Dubbo 缺省会在启动时检查依赖的服务是否可用,不可用时会抛出异常,阻止 Spring 初始化完成,以便上线时,能够及早发现问题,默认 check="true"
。
可以通过 check="false"
关闭检查,比如,测试时,有些服务不关心,或者是出现了循环依赖,必须有一方先启动
另外,如果你的 Spring 容器是懒加载的,或者通过 API 编程延迟服务,则需要关闭 Check,否则服务临时不可用时,会抛出异常,拿到 null
饮用,如果 `check=false,总是会返回引用,当服务恢复时,能自动连上。
示例:
对于Spring 配置文件
dubbo.xml
关闭某个服务的启动时检查(没有提供者时报错)
<dubbo:reference interface="com.yourname.mall.service.UserService" id="userService" check="false" />
关闭所有服务的启动时检查(没有提供者时报错)
<dubbo:consumer check="false" />
关闭注册中心启动时检查(注册订阅失败时报错)
<dubbo:registry check="false" />
通过
dubbo.properties
dubbo.reference.com.yourname.mall.service.BaseService.check=false dubbo.reference.check=false dubbo.consumer.check=false dubbo.registry.check=false
通过
-D
参数$ java -Ddubbo.reference.com.yourname.mall.service.BaseService.check=false $ java -Ddubbo.reference.check=false $ java -Ddubbo.consumer.check=false $ java -Ddubbo.registry.check=false
对于 SpringBoot 配置文件
application.properties
/application.yaml
dubbo: reference: com: yourname: mall: service: BaseService: check: false check: false consumer: check: false registry: check: false
配置的含义:
dubbo.reference.check=false
:强制改变所有 reference
的 check
值,就算配置中有声明,也会被覆盖
dubbo.consumer.check=false
:是设置 check
的缺省值,如果配置中有显式的声明,如 <dubbo:reference check="true" />
不会受影响。
dubbo.registry.check=false
:前面两个都是指订阅成功,但是提供者列表是否为空是否报错,如果订阅失败时,也允许启动,需要使用此选项,将在后台定时重试。
4. 超时
当服务消费者引用服务提供者时,可能由于网络原因,需要执行很长一段时间,如果长时间都没有返回,可能会导致大量线程阻塞,从而引起性能下降,为了解决这个问题,我们可以指定一个超时属性(timeout
)
示例:
设置某个服务的超时时间为
3000ms
(可选属性,默认使用<dubbo:consumer>
中的timeout
)<dubbo:reference interface="com.yourname.mall.service.UserService" id="userService" timeout="3000" />
设置某个服务中的某个方法的超时时间为
3000ms
<dubbo:reference interface="com.yourname.mall.service.UserService" id="userService"> <dubbo:method name="getUserAddressList" timeout="3000" /> </dubbo:reference>
设置所有服务的超时时间为
3000ms
<dubbo:consumer timeout="3000" />
5. 重试次数
重试次数(retries
)通常会结合超时属性一起使用。当某一个服务由于网络不佳或者是服务运行缓慢导致超时,远程调用失败时,可以通过设置重试次数来进行多次尝试,重试次数不包含第一次调用,0
代表不重试
通常在幂等方法下,建议设置重试次数以来提升系统性能,而在非幂等方法下,则不建议设置重试次数,以免出现结果不一致的情况
幂等方法:无论运行多少次,最终都是一个结果,如:查询、删除、修改方法
非幂等方法:每一次运行的最终结果都不一致,如:新增方法
示例:
设置某个服务的超时时间为
3000ms
,重试3
次<dubbo:reference interface="com.yourname.mall.service.UserService" id="userService" timeout="3000" retries="3" />
设置某个服务中的某个方法的超时时间为
3000ms
,重试3
次<dubbo:reference interface="com.yourname.mall.service.UserService" id="userService"> <dubbo:method name="getUserAddressList" timeout="3000" retries="3" /> </dubbo:reference>
设置所有服务的超时时间为
3000ms
,重试3
次<dubbo:consumer timeout="3000" retries="3" />
6. 多版本
在 Dubbo 中为同一个服务配置多个版本,当一个接口实现,出现不兼容升级时,可以用版本号过渡,版本号不同的服务相互间不引用。
可以按照以下的步骤进行版本迁移:
- 在低压力时间段,先升级一半提供者为新版本
- 再将所有消费者升级为新版本
- 然后将剩下的一半提供者升级为新版本
示例:
老版本服务提供者配置:
<dubbo:service interface="com.yourname.mall.service.UserService" version="1.0.0" />
新版本服务提供者配置:
<dubbo:service interface="com.yourname.mall.service.UserService" version="2.0.0" />
老版本服务消费者配置:
<dubbo:reference id="barService" interface="com.yourname.mall.service.UserService" version="1.0.0" />
新版本服务消费者配置:
<dubbo:reference id="userService" interface="com.yourname.mall.service.UserService" version="2.0.0" />
如果不需要区分版本,可以按照以下的方式配置 [^1]:
[^1]:提示:需要2.2.0
以上版本支持
<dubbo:reference id="userService" interface="com.yourname.mall.service.UserService" version="*" />
7. 本地存根
远程服务后,客户端通常只剩下接口,而实现全在服务器端,但提供方有些时候想在客户端也执行部分逻辑,比如:做 ThreadLocal 缓存,提前验证参数,调用失败后伪造容错数据等等,此时就需要在 API 中带上 Stub,客户端生成 Proxy 实例,会把 Proxy 通过构造函数传给 Stub[^2],然后把 Stub 暴露给用户,Stub 可以决定要不要去调 Proxy。
本地存根通常会放在 API 包中方便调用
示例:
在 Spring 配置文件中按以下方式配置:
<dubbo:service interface="com.yourname.service.BarService" stub="true" />
<dubbo:service interface="com.yourname.service.BarService" stub="com.yourname.service.BarServiceStub" />
提供 Stub 的实现[^3]:
public class UserServiceStub implements UserService {
private final UserService userService;
// 构造函数传入真正的远程代理对象
public UserServiceStub(UserService userService){
this.userService = userService;
}
public String getUserAddressList(String userId) {
// 此代码在客户端执行, 你可以在客户端做ThreadLocal本地缓存,或预先验证参数是否合法,等等
try {
return userService.getUserAddressList(userId);
} catch (Exception e) {
// 你可以容错,可以做任何AOP拦截事项
return "容错数据";
}
}
}
[^2]:Stub 必须有可传入 Proxy 的构造函数。
[^3]:在 interface 旁边放一个 Stub 实现,它实现 BarService
接口,并有一个传入远程 BarService
实例的构造函数
8. Dubbo 与 SpringBoot 整合的三种方式
Dubbo 与 SpringBoot 整合的三种方式
导入
dubbo-spring-boot-starter
,在application.properties
/application.yaml
中配置属性,使用@DubboService
注解暴露服务,使用@DubboReference
注解引用服务(需要使用@EnableDubble
开启基于注解的 Dubbo 功能,如果想要对某一个方法进行详细配置的话可以在@DubboService
或者是@DubboReference
的methods
参数中设置:{@Method(name = "getUserAddressList", timeout = 10000, retries = 5)}
来实现)保留
dubbo.xml
配置文件,使用@ImportResource(locations = "classpath:dubbo.xml")
导入原始 XML 配置文件使用注解 API 的方式,将每一个组件手动创建到容器中,让 Dubbo 来扫描其他的组件
创建一个配置类
@Configuration public class MyDubboConfig { @Bean public ApplicationConfig applicationConfig() { ApplicationConfig applicationConfig = new ApplicationCOnfig(); applicationConfig.setName("boot-user-service-provider"); return applicationVonfig } @Bean public RegistryConfig registryConfig() { RegistryConfig registryConfig = new RegistryConfig(); registryConfig.setProtocol("zookeeper"); registryConfig.setAddress("127.0.0.1:2181"); return registryConfig } @Bean public protocolConfig protocolConfig() { ProtocolConfig protocolConfig = new protocolConfig(); protocolConfig.setName("dubbo"); protocolConfig.setPort(20882); return protocolConfig } @Bean public ServiceCopnfig<UserService> serviceConfig(UserService userService) { ServiceCopnfig<UserService> serviceConfig = new ServiceCopnfig<>(); serviceConfig.setInterface(UserService.class); serviceConfig.setRef(userService); serviceConfig.setVersion("1.0.0"); // 编写每一个 Method 信息 MethodConfig methodConfig = new MethodConfig(); methodConfig.setName("getUserAddressList"); methodConfig.setTimeout(10000); // 将 Method 的设置关联到 Service 配置中 serviceConfig.setMethods(Arrays.asList(methodConfig)); // ProviderConfig // MonitorConfig // ... return serviceConfig } }
设置包扫描
@EnableDubbo(sacnBasePackages = "com.yourname.mall")
使用
@DubboService
暴露服务