配置中心是dubbo3三大中心之一,在dubbo3的实例级服务注册发现中承担着配置管理的主要角色;dubbo3的配置中心有两种作用,一是类似于dubbo.properties文件一样,做为启动时配置参数加载,二是通过监听机制实现一些策略规则的动态变更。
配置中心启动
启动流程
配置中心的启动入口在DefaultApplicationDeplyer.initialize()方法中,initialize()方法调用startConfigCenter()方法,时序图如下:
主要流程有:
1、从环境配置(dubbo.properties,系统参数,jvm参数,springboot配置等)中读取配置中心的配置
2、如果没有配置中心配置,则尝试使用注册中心做为配置中心
3、刷新配置中心配置
4、创建配置中心对应的DynamicConfiguration对象,并通过DynamicConfiguration对象尝试从配置中心获取类似dubbo.properties的配置覆盖掉现在有的配置(以zookeeper为例,分别有:/dubbo/config/dubbo/dubbo.properties 和 /dubbo/config/{applicationName}|dubbo.properties)。
5、将配置中心对应的DynamicConfiguration添加天环境(Environment对象)中,与dubbo.properties,系统参数,jvm参数,springboot配置等配置配合使用。
DynamicConfiguration
该类型是配置中心的一个包装对象,抽象了配置中心的所有数据获取和动态变更监听功能,主要的方法有如下几个:
- getProperties(String, String, long)
dubbo3 在启动的时候通过该方法从配置中心获取配置文件的内容。 - getProperty(String, Object)
匹配单个配置项,用于内容小的配置项 - getConfig(String, String, long)
匹配特定的配置,用于内容多且复杂的富配置项。例如启动时的配置文件和治理规则等。 - addListener(String, String, ConfigurationListener)/removeListener(String, String, ConfigurationListener)
添加或者删除需要监听的治理规则和配置项的监听器,实现动态变更
Environment配置
该对象是dubbo3运行时的配置管理对象,几乎是所有的配置都在该类中维护,获取配置也基本上都是从该类获取。
该类通过两个CompositeConfiguration对象来分别管理配置中心的配置和所有的配置(包含本地相关的配置),分别是Environment的defaultDynamicConfiguration字段和defaultDynamicGlobalConfiguration字段。
- defaultDynamicConfiguration
维护配置中心的DynamicConfiguration,在DefaultApplicationDeployer.startConfigCenter()方法中,将配置中心加载后,调用Environment.setDynamicConfiguration()方法传给Environment。 - defaultDynamicGlobalConfiguration
维护着全局的Configuration对象,在Environment.getDynamicGlobalConfiguration()方法创建,将defaultDynamicConfiguration添加在前,后再添加本地相关的Configuration对象,这样会优先读取配置中心的配置。
本地相关的Configuration目前有六个,优先级从上到下:
- systemConfiguration
SystemConfiguration类型,从系统参数( System.getProperties()/System.getProperty() )中返回配置 - environmentConfiguration
EnvironmentConfiguration类型,从系统环境( System.getEnv() )中获取配置 - appExternalConfiguration
nmemoryConfiguration类型,有两处来源:
1、配置中心对应的ConfigCenterConfug对应的appExternalConfiguration字段,该字段是Map类型
2、从配置中心读取的应用的dubbo.properties内容 (以zookeeper配置中心为例,路径是/dubbo/config/{applicationName}/dubbo.properties) - externalConfiguration
InmemoryConfiguration类型,有两处来源:
1、配置中心对应的ConfigCenterConfug对应的externalConfiguration字段,该字段是Map类型
2、从配置中心读取的dubbo.properties内容 (以zookeeper配置中心为例,路径是/dubbo/config/dubbo/dubbo.properties) - appConfiguration
InmemoryConfiguration类型,应用的配置。在springboot框架下运行时,会加载springboot的application.yaml中的配置,由DubboInfraBeanRegisterPostProcessor.postProcessBeanFactory()触发 - propertiesConfiguration
PropertiesConfiguration类型,从dubbo.properties文件读取配置
代码如下:
@Override
public void initialize() throws IllegalStateException {
if (initialized.compareAndSet(false, true)) {
this.propertiesConfiguration = new PropertiesConfiguration(scopeModel);
this.systemConfiguration = new SystemConfiguration();
this.environmentConfiguration = new EnvironmentConfiguration();
this.externalConfiguration = new InmemoryConfiguration("ExternalConfig");
this.appExternalConfiguration = new InmemoryConfiguration("AppExternalConfig");
this.appConfiguration = new InmemoryConfiguration("AppConfig");
loadMigrationRule();
}
}
/**
* There are two ways to get configuration during exposure / reference or at runtime:
* 1. URL, The value in the URL is relatively fixed. we can get value directly.
* 2. The configuration exposed in this method is convenient for us to query the latest values from multiple
* prioritized sources, it also guarantees that configs changed dynamically can take effect on the fly.
*/
public CompositeConfiguration getConfiguration() {
if (globalConfiguration == null) {
CompositeConfiguration configuration = new CompositeConfiguration();
configuration.addConfiguration(systemConfiguration);
configuration.addConfiguration(environmentConfiguration);
configuration.addConfiguration(appExternalConfiguration);
configuration.addConfiguration(externalConfiguration);
configuration.addConfiguration(appConfiguration);
configuration.addConfiguration(propertiesConfiguration);
globalConfiguration = configuration;
}
return globalConfiguration;
}
public Configuration getDynamicGlobalConfiguration() {
if (defaultDynamicGlobalConfiguration == null) {
if (defaultDynamicConfiguration == null) {
if (logger.isWarnEnabled()) {
logger.warn("dynamicConfiguration is null , return globalConfiguration.");
}
return getConfiguration();
}
defaultDynamicGlobalConfiguration = new CompositeConfiguration();
defaultDynamicGlobalConfiguration.addConfiguration(defaultDynamicConfiguration); // 先添加配置中心的Configuration对象,使配置中心的配置优先级更高
defaultDynamicGlobalConfiguration.addConfiguration(getConfiguration()); //再添加本地相关的配置
}
return defaultDynamicGlobalConfiguration;
}
配置中心-zookeeper路径参考
配置
路径 | 备注 | side | 维护意见 |
/dubbo/config/dubbo/dubbo.properties | dubbo配置,与dubbo.properties文件的功能一样,但影响范围是所有的dubbo应用 | provider consumer | 所有应用可见,该配置会影响dubbo的启动逻辑 |
/dubbo/config/{applicationName}/dubbo.properties | dubbo配置,与dubbo.properties文件一样,但只对指定的应用生效 | provider consumer | 对应应用可见,该配置会影响dubbo的启动逻辑 |
/dubbo/config/dubbo.application.register-mode | 注册模式,所有应用 | provider | 所有应用可见,配置中心优先,默认是all,即应用级和接口级都会注册 |
/dubbo/config/dubbo.application.migration.step | MigrationStep | consumer | 所有应用可见,配置中心优先,默认是APPLICATION_FIRST |
/dubbo/config/dubbo.service-discovery.migration | MigrationStep | consumer | 同/dubbo/config/dubbo.application.migration.step一样,当/dubbo/config/dubbo.application.migration.step没有获取到值时,会尝试从该配置项取值 |
治理规则
以下规则主要是为dubbo3的服务治理提供配置,会影响注册时URL参数以及RPC的URL参数和路由
路径 | 备注 | side |
/dubbo/config/dubbo/{applicationName}.configurators | 应用export时使用的configurators URL, 该路径会被RegistryProtocol\$ProviderConfigurationListener监听 消费端应用订阅Dubbo Service时的configurators URL,该路径被ServiceDiscoveryRegistryDirectory\$ConsumerConfigurationListener监听 | provider consumer |
/dubbo/config/dubbo/{interface}:{version}:{group}.configurations | 接口的configurators URL,该路径会被RegistryProtocol\$ServiceConfigurationListener和ServiceDiscoveryRegistryDirectory\$ReferenceConfigurationListener监听 | provider consumer |
/dubbo/config/DUBBO_SERVICEDISCOVERY_MIGRATION/{applicationName}.migration | 应用的migration规则,该路由被MigrationRuleListener监听 | consumer |
/dubbo/config/dubbo/{interface}:{version}:{group}.condition-router | 条件路由规则,该路径被ServiceStateRouter监听 | consumer |
/dubbo/config/dubbo/{applicationName}.condition-router | 条件路由规则,该路径被AppStateRouter监听 | consumer |
/dubbo/config/dubbo/{providerApplicationName}.tag-router | provider的标签路由规则,该路径被TagStateRouter监听 | consumer |
/dubbo/config/dubbo/{applicationName}.MESHAPPRULE | mesh的路由规则, 该路径被MeshAppRuleListener监听 | consumer |