订阅创建代理的第一部分
红框之前的部分已经分析过,本文分析红框内的部分。
private <T> Invoker<T> doRefer(Cluster cluster, Registry registry, Class<T> type, URL url) {
RegistryDirectory<T> directory = new RegistryDirectory<T>(type, url);//保存并解析了订阅信息。
directory.setRegistry(registry);
directory.setProtocol(protocol);
// all attributes of REFER_KEY
Map<String, String> parameters = new HashMap<String, String>(directory.getUrl().getParameters());
URL subscribeUrl = new URL(Constants.CONSUMER_PROTOCOL, parameters.remove(Constants.REGISTER_IP_KEY), 0, type.getName(), parameters);
if (!Constants.ANY_VALUE.equals(url.getServiceInterface())
&& url.getParameter(Constants.REGISTER_KEY, true)) {
//注册consumer订阅信息
registry.register(subscribeUrl.addParameters(Constants.CATEGORY_KEY, Constants.CONSUMERS_CATEGORY,
Constants.CHECK_KEY, String.valueOf(false)));
}
//订阅并获取 服务端列表,配置,路由信息。然后连接服务端,并创建执行代理的invoker
directory.subscribe(subscribeUrl.addParameter(Constants.CATEGORY_KEY,
Constants.PROVIDERS_CATEGORY
+ "," + Constants.CONFIGURATORS_CATEGORY
+ "," + Constants.ROUTERS_CATEGORY));
//创建容错层
Invoker invoker = cluster.join(directory);
ProviderConsumerRegTable.registerConsumer(invoker, url, subscribeUrl, directory);
return invoker;
}
注意方法中黑体的部分,本文将围绕 这几个部分逐个分析
- 保存并解析了订阅信息。
- 注册consumer订阅信息
- 订阅并获取 服务端列表,配置,路由信息。然后连接服务端,并创建执行代理的invoker
- 创建容错层
RegistryDirectory创建分析
执行 RegistryProtocol.doRefer(Cluster, Registry, Class<T>, URL) 时创建,代码如下
RegistryDirectory<T> directory = new RegistryDirectory<T>(type, url);
directory.setRegistry(registry);
directory.setProtocol(protocol);
public RegistryDirectory(Class<T> serviceType, URL url) {
super(url);//保存url
if (serviceType == null)
throw new IllegalArgumentException("service type is null.");
if (url.getServiceKey() == null || url.getServiceKey().length() == 0)
throw new IllegalArgumentException("registry serviceKey is null.")
this.serviceType = serviceType;
this.serviceKey = url.getServiceKey();
//解析引用参数为map, 解析前的引用参数 url.getParameterAndDecoded(Constants.REFER_KEY): application=young-app&default.timeout=30000000&dubbo=2.6.2&interface=tuling.dubbo.server.UserService&loadbalance=consistenthash&methods=getUser&pid=25060&qos.enable=false®ister.ip=169.254.23.140&side=consumer&timeout=30000000×tamp=1573355812993
this.queryMap = StringUtils.parseQueryString(url.getParameterAndDecoded(Constants.REFER_KEY));
//url.setPath(url.getServiceInterface()).clearParameters()结果: zookeeper://127.0.0.1:2181/com.alibaba.dubbo.registry.RegistryService
//addParameters 将引用参数拼接在zookeeper://127.0.0.1:2181/com.alibaba.dubbo.registry.RegistryService后面
this.overrideDirectoryUrl = this.directoryUrl = url.setPath(url.getServiceInterface()).clearParameters().addParameters(queryMap).removeParameter(Constants.MONITOR_KEY);
String group = directoryUrl.getParameter(Constants.GROUP_KEY, "");
this.multiGroup = group != null && ("*".equals(group) || group.contains(","));//获取是否 配置多组
String methods = queryMap.get(Constants.METHODS_KEY);
this.serviceMethods = methods == null ? null : Constants.COMMA_SPLIT_PATTERN.split(methods);//解析方法名数组
}
创建 RegistryDirectory的过程就是保存并解析了订阅信息。
RegistryDirectory<T>.mergeUrl(URL) 分析
private URL mergeUrl(URL providerUrl) {
providerUrl = ClusterUtils.mergeUrl(providerUrl, queryMap); // Merge the consumer side parameters 合并 consumer端的参数
List<Configurator> localConfigurators = this.configurators; // local reference
if (localConfigurators != null && !localConfigurators.isEmpty()) {// 通过配置 更改providerUrl,需要详细分析。
for (Configurator configurator : localConfigurators) {
providerUrl = configurator.configure(providerUrl);
}
}
//不检查连接是否成功,总是创建invoker
providerUrl = providerUrl.addParameter(Constants.CHECK_KEY, String.valueOf(false));
// The combination of directoryUrl and override is at the end of notify, which can't be handled here
this.overrideDirectoryUrl = this.overrideDirectoryUrl.addParametersIfAbsent(providerUrl.getParameters()); //合并provider 的参数到overrideDirectoryUrl
if ((providerUrl.getPath() == null || providerUrl.getPath().length() == 0)// version 1.0 可能出现providerUrl path 为空的情况
&& "dubbo".equals(providerUrl.getProtocol())) { // Compatible version 1.0
//fix by tony.chenl DUBBO-44
String path = directoryUrl.getParameter(Constants.INTERFACE_KEY);
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;
}
方法逻辑:合并consumer参数到 provoider 代表的providerUrl
ClusterUtils
将localMap的参数合并到remoteUrl中,将remoteUrl中的 filters and listeners合并到localMap中
public static URL mergeUrl(URL remoteUrl, Map<String, String> localMap) {
Map<String, String> map = new HashMap<String, String>();
Map<String, String> remoteMap = remoteUrl.getParameters();
if (remoteMap != null && remoteMap.size() > 0) {
map.putAll(remoteMap);
//一些参数 必须以localMap为准,移除被provider影响的参数
// Remove configurations from provider, some items should be affected by provider.
map.remove(Constants.THREAD_NAME_KEY);
map.remove(Constants.DEFAULT_KEY_PREFIX + Constants.THREAD_NAME_K