在consumer侧,RPC参数的优先级如下: referenceconfig > consumerconfig > moduleconfig > applicationconfig > provider url
关于referenceconfig 到 applicationconfig这部分优先级处理逻辑是在ReferenceConfig中处理的,在ReferenceConfig创建Proxy对象时,有一段加载consumer url参数配置的代码:
public class ReferenceConfigextends ReferenceConfigBase { public class ReferenceConfig extends ReferenceConfigBase { ... Map referenceParameters = appendConfig(); initServiceAppsMapping(referenceParameters); ... ref = createProxy(referenceParameters); ... } private Map appendConfig() { Map map = new HashMap<>(16); ... AbstractConfig.appendParameters(map, getApplication()); AbstractConfig.appendParameters(map, getModule()); AbstractConfig.appendParameters(map, consumer); AbstractConfig.appendParameters(map, this); appendMetricsCompatible(map); ... return map; } }
对于consumer url覆盖provider url的处理有两种,分别对就在了接口级和实例级,接口级的覆盖逻辑在RegistryDirectory中,会先执行完url合并,然后再调用Protocol.refer(serviceType, margedUrl)创建Invokder对象;代码如下:
public class RegistryDirectoryextends DynamicDirectory { private Map > toInvokers(Map > oldUrlInvokerMap, List urls) { Map > newUrlInvokerMap = new ConcurrentHashMap<>(urls == null ? 1 : (int) (urls.size() / 0.75f + 1)); if (urls == null || urls.isEmpty()) { return newUrlInvokerMap; } String queryProtocols = this.queryMap.get(PROTOCOL_KEY); for (URL providerUrl : urls) { ... URL url = mergeUrl(providerUrl); // Cache key is url that does not merge with consumer side parameters, regardless of how the consumer combines parameters, if the server url changes, then refer again Invoker invoker = oldUrlInvokerMap == null ? null : oldUrlInvokerMap.remove(url); if (invoker == null) { // Not in the cache, refer again boolean enabled = true; if (url.hasParameter(DISABLED_KEY)) { enabled = !url.getParameter(DISABLED_KEY, false); } else { enabled = url.getParameter(ENABLED_KEY, true); } if (enabled) { // 创建Invokder对象 invoker = protocol.refer(serviceType, url); } ... if (invoker != null) { // Put new invoker in cache newUrlInvokerMap.put(url, invoker); } ... } } return newUrlInvokerMap; } private URL mergeUrl(URL providerUrl) { if (providerUrl instanceof ServiceAddressURL) { providerUrl = overrideWithConfigurator(providerUrl); } else { // 合并 consumer 侧 parameters providerUrl = applicationModel.getBeanFactory().getBean(ClusterUtils.class).mergeUrl(providerUrl, queryMap); // Merge the consumer side parameters providerUrl = overrideWithConfigurator(providerUrl); providerUrl = providerUrl.addParameter(Constants.CHECK_KEY, String.valueOf(false)); // Do not check whether the connection is successful or not, always create Invoker! } // FIXME, kept for mock if (providerUrl.hasParameter(MOCK_KEY) || providerUrl.getAnyMethodParameter(MOCK_KEY) != null) { providerUrl = providerUrl.removeParameter(TAG_KEY); } if ((providerUrl.getPath() == null || providerUrl.getPath() .length() == 0) && DUBBO_PROTOCOL.equals(providerUrl.getProtocol())) { // Compatible version 1.0 //fix by tony.chenl DUBBO-44 String path = directoryUrl.getServiceInterface(); if (path != null) { int i = path.indexOf('/'); if (i >= 0) { path = path.substring(i + 1); } i = path.lastIndexOf(':'); if (i >= 0) { path = path.substring(0, i); } providerUrl = providerUrl.setPath(path); } } return providerUrl; } }
实例级服务发现场景中使用的是ServiceDiscoveryRegistryDirectory和InstanceAddressURL,对于consumer side parameters和provider side parameters也是做了更灵活的处理,主要逻辑是InstanceAddressURL中,会先判断parameterKey是否为provider side优先,如果不是,则优先从consumer side parameters中取值;代码如下:
public class InstanceAddressURL extends URL {
@Override
public String getParameter(String key) {
...
// 判断是否优先从consumer side 取
if (consumerParamFirst(key)) {
URL consumerUrl = RpcContext.getServiceContext().getConsumerUrl();
if (consumerUrl != null) {
String v = consumerUrl.getParameter(key);
if (StringUtils.isNotEmpty(v)) {
return v;
}
}
}
String protocolServiceKey = getProtocolServiceKey();
if (isEmpty(protocolServiceKey)) {
return getInstanceParameter(key);
}
return getServiceParameter(protocolServiceKey, key);
}
private boolean consumerParamFirst(String key) {
if (CollectionUtils.isNotEmpty(providerFirstParams)) {
return !providerFirstParams.contains(key);
} else {
return true;
}
}
}
在InstanceAddressURL中会先通过providerFirstParams进行判断,InstanceAddressURL.providerFirstParams是由ServiceDiscoveryRegistryDirectory赋值的,代码如下:
public class ServiceDiscoveryRegistryDirectoryextends DynamicDirectory { public ServiceDiscoveryRegistryDirectory(Class serviceType, URL url) { super(serviceType, url); moduleModel = getModuleModel(url.getScopeModel()); // ProviderFirstParams SPI Set providerFirstParams = url.getOrDefaultApplicationModel().getExtensionLoader(ProviderFirstParams.class).getSupportedExtensionInstances(); if (CollectionUtils.isEmpty(providerFirstParams)) { this.providerFirstParams = null; } else { if (providerFirstParams.size() == 1) { this.providerFirstParams = Collections.unmodifiableSet(providerFirstParams.iterator().next().params()); } else { Set params = new HashSet<>(); for (ProviderFirstParams paramsFilter : providerFirstParams) { if (paramsFilter.params() == null) { break; } params.addAll(paramsFilter.params()); } this.providerFirstParams = Collections.unmodifiableSet(params); } } } private Map > toInvokers(Map > oldUrlInvokerMap, List urls) { Map > newUrlInvokerMap = new ConcurrentHashMap<>(urls == null ? 1 : (int) (urls.size() / 0.75f + 1)); if (urls == null || urls.isEmpty()) { return newUrlInvokerMap; } for (URL url : urls) { InstanceAddressURL instanceAddressURL = (InstanceAddressURL) url; ... //InstanceAddressURL对象设置providerFirstParams instanceAddressURL.setProviderFirstParams(providerFirstParams); // Override provider urls if needed if (enableConfigurationListen) { instanceAddressURL = overrideWithConfigurator(instanceAddressURL); } ... invoker = protocol.refer(serviceType, instanceAddressURL); ... } return newUrlInvokerMap; } }
如果要设置provider 优先字段可以通过实现ProviderFirstParams SPI 添加,默认的DefaultProviderFirstParams设置了5个provider 优先字段:release, dubbo, methods, timestamp, tag
代码如下:
public class DefaultProviderFirstParams implements ProviderFirstParams {
private final static Set PARAMS = Collections.unmodifiableSet(new HashSet() {{
addAll(Arrays.asList(RELEASE_KEY, DUBBO_VERSION_KEY, METHODS_KEY, TIMESTAMP_KEY, TAG_KEY));
}});
@Override
public Set params() {
return PARAMS;
}
}



