dubbo源码分析1-consumer代理创建和连接分析1

 

创建代理和连接server详细分析

由于整个过程超级复杂,整个分析的思路是先整体再局部,将复杂的流程拆分为多个部分逐个分析,这样比较容易理解。

整理连接server流程图如下

如果直连方式直接调用 DubboProtocol,如果配置了注册中心则通过注册中心获取 server url列表。然后调用DubboProtocol。(DubboProtocol代表与服务端建立连接创建执行代理invoker, 其中包含了创建过滤链的流程。)

线上 我们常用的是 订阅创建代理方式 与服务端通信,所以我们的目标是分析阅创建代理过程。

由于订阅创建代理完整的时序特别长,总结出下图

如上图可以分为3个节点

  1. 获取执行代理inovker,创建动态代理.
  2. 向注册中心订阅服务端信息
  3. 与服务端建立连接创建执行代理invoker

 

对应下图的 1,2,3

 

这个图是简略时序图,图中只给出一些关键的步骤。

订阅创建代理分析计划

先分析创建动态代理,然后分析直连创建代理,最后分析订阅创建代理

这样做的原因 先分析创建动态代理 是对整个流程的切入点有了解,知道有那些内容需要分析。

订阅创建代理流程很复杂。包含了直连创建代理的流程,先分析这部分,有助于后续的分析。

创建动态代理分析

代理类方法 createProxy 分析

loc:ReferenceConfig<T>.createProxy(Map<String,String>)

createProxy:创建代理类,详细处理如下

判断是否是InJVM,如果是就创建InJVM类型 invoker, 否则如果是直连方式,解析直连配置字符串,获取连接列表,走直接方式创建Invoker,否则如果是注册中心方式,获取多个注册中心配置列表 走订阅流程创建Invoker,然后使用javasist生成代理类型。

@SuppressWarnings({"unchecked", "rawtypes", "deprecation"})

private T createProxy(Map<String, String> map) {

 

URL tmpUrl = new URL("temp", "localhost", 0, map);

//...

//直连的方式也可以配置注册中心,根据是否配置注册中心做不同的处理

if (Constants.REGISTRY_PROTOCOL.equals(url.getProtocol())) {

urls.add(url.addParameterAndEncoded(Constants.REFER_KEY, StringUtils.toQueryString(map)));//添加必要属性

} else {

// url=dubbo://10.103.11.210:20880/tuling.dubbo.server.UserService

// map toString:{dubbo=2.5.7, timestamp=1551177583993, methods=getUser, register.ip=10.103.11.210, application=young-app, side=consumer, pid=9052, interface=tuling.dubbo.server.UserService, loadbalance=roundrobin}

//url在 直连时 是set进来的 。合并map到url中去

urls.add(ClusterUtils.mergeUrl(url, map));

}

}

}

} else {

// 配置了注册中心,将注册中心的配置 附加基本配置,组装成注册中心配置列表(有可能配置了多个注册中心)

List<URL> us = loadRegistries(false);

if (us != null && us.size() > 0) {

//添加监控中心地址

for (URL u : us) {

URL monitorUrl = loadMonitor(u);

if (monitorUrl != null) {

map.put(Constants.MONITOR_KEY, URL.encode(monitorUrl.toFullString()));

}

urls.add(u.addParameterAndEncoded(Constants.REFER_KEY, StringUtils.toQueryString(map)));

}

}

if (urls == null || urls.size() == 0) {//抛出异常

throw new IllegalStateException("No such any registry to reference " + interfaceName + " on the consumer " + NetUtils.getLocalHost() + " use dubbo version " + Version.getVersion() + ", please config <dubbo:registry address=\"...\" /> to your spring config.");

}

}

 

if (urls.size() == 1) {

//创建执行代理invoker,配置注册中心则返回 MockClusterInovoker 否则返回ProtocolFilterWrapper$1 invoker

invoker = refprotocol.refer(interfaceClass, urls.get(0));

} else {

List<Invoker<?>> invokers = new ArrayList<Invoker<?>>();

URL registryURL = null;

for (URL url : urls) {

invokers.add(refprotocol.refer(interfaceClass, url));

if (Constants.REGISTRY_PROTOCOL.equals(url.getProtocol())) {

registryURL = url; // 用了最后一个registry url

}

}

//直连的方式配置了注册中心

if (registryURL != null) { // 有 注册中心协议的URL

// 对有注册中心的Cluster 只用 AvailableCluster

URL u = registryURL.addParameter(Constants.CLUSTER_KEY, AvailableCluster.NAME);//指定容错层,AvailableCluster在执行时会检查invoker是否可用

//StaticDirectory 静态目录 相对于RegistryDirectory 而言,里面的invoker列表是不可改变的。

invoker = cluster.join(new StaticDirectory(u, invokers));

} else { // 不是 注册中心的URL

invoker = cluster.join(new StaticDirectory(invokers));

}

}

}

 

Boolean c = check;

if (c == null && consumer != null) {//获取配置是否检查

c = consumer.isCheck();

}

if (c == null) {//默认检查

c = true; // default true

}// 如果检查 但是invoker不可用。抛出异常

if (c && !invoker.isAvailable()) {

throw new IllegalStateException("Failed to check the status of the service " + interfaceName + ". No provider available for the service " + (group == null ? "" : group + "/") + interfaceName + (version == null ? "" : ":" + version) + " from the url " + invoker.getUrl() + " to the consumer " + NetUtils.getLocalHost() + " use dubbo version " + Version.getVersion());

}

// 创建服务代理

return (T) proxyFactory.getProxy(invoker);

}

 

 

 

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值