前面我们学习了Dubbo源码解析之服务端Provider。对服务提供方进行思路上的讲解,我们知道以下知识点。本篇文章主要对消费方进行讲解。废话不多说请看下文。

  • 如何将对象方法生成Invoker
  • 如何将Invoker注册到注册地中心
  • 如何处理客户端的请求
  • 二进制数据转java数据协议
  • 协议中包含的序列化知识

一、启动一个客户端Consumer

1. 定义一个接口

注意这里其实是引用的前文中的接口。生产中是服务提供方打一个jar包给客户端用。

@Testpublic void consumerTest() {    // 当前应用配置    ApplicationConfig application = new ApplicationConfig();    application.setName("consumerTest");    // 连接注册中心配置    RegistryConfig registry = new RegistryConfig();    registry.setAddress("zookeeper://127.0.0.1:2181");    // 注意:ReferenceConfig为重对象,内部封装了与注册中心的连接,以及与服务提供方的连接    // 引用远程服务    ReferenceConfig reference = new ReferenceConfig(); // 此实例很重,封装了与注册中心的连接以及与提供者的连接,请自行缓存,否则可能造成内存和连接泄漏    reference.setApplication(application);    reference.setRegistry(registry); // 多个注册中心可以用setRegistries()    reference.setInterface(UserService.class);    reference.setVersion("1.0.0");    UserService userService = reference.get();    userService.say("hello");}

2. 生成本地服务

@Testpublic void consumerTest() {    // 当前应用配置    ApplicationConfig application = new ApplicationConfig();    application.setName("consumerTest");    // 连接注册中心配置    RegistryConfig registry = new RegistryConfig();    registry.setAddress("zookeeper://127.0.0.1:2181");    // 注意:ReferenceConfig为重对象,内部封装了与注册中心的连接,以及与服务提供方的连接    // 引用远程服务    ReferenceConfig reference = new ReferenceConfig(); // 此实例很重,封装了与注册中心的连接以及与提供者的连接,请自行缓存,否则可能造成内存和连接泄漏    reference.setApplication(application);    reference.setRegistry(registry); // 多个注册中心可以用setRegistries()    reference.setInterface(UserService.class);    reference.setVersion("1.0.0");    UserService userService = reference.get();    userService.say("hello");}

3. 原理分析

首先客户端只有接口的,那么可以根据这个接口生成一个代理。而代理对象的逻辑就是,从zk中找到服务端地址。
然后通过netty客户端去请求服务端的数据。然后返回

二、源码分析

带着我们猜测的逻辑一起来看下ReferenceConfig的实现原理。

public synchronized T get() {      if (destroyed){          throw new IllegalStateException("Already destroyed!");      }  if (ref == null) {      //逻辑就在init里面  init();  }  return ref;  }

init先做写检查信息,如这个方法是否存在接口中
createProxy#loadRegistries

1. 集群容错策略

注意只有多个服务提供方才会有这里,只有一个服务提供方,没办法容错处理哈。

可以看到一共有9种策略。

当时服务端是多个的时候,才会生成集群策略。另外既然是集群就要选择到底使用哪个来执行。这就是
负载均衡或者说叫路由策略。

LoadBalance负载均衡

  • directory中获取所有的invoker
  • 如果有多个invoker就去看配置的负载均衡策略
  • 根据负载均衡策略找到一个Inoker
public abstract class AbstractClusterInvoker implements Invoker {    public Result invoke(final Invocation invocation) throws RpcException {        checkWheatherDestoried();        LoadBalance loadbalance;        //获取所有的invoker        List> invokers = list(invocation);        //如果有多个invoker就去看配置的负载均衡策略        if (invokers != null && invokers.size() > 0) {            loadbalance = ExtensionLoader.getExtensionLoader(LoadBalance.class).getExtension(invokers.get(0).getUrl()                    .getMethodParameter(invocation.getMethodName(),Constants.LOADBALANCE_KEY, Constants.DEFAULT_LOADBALANCE));        } else {            loadbalance = ExtensionLoader.getExtensionLoader(LoadBalance.class).getExtension(Constants.DEFAULT_LOADBALANCE);        }        RpcUtils.attachInvocationIdIfAsync(getUrl(), invocation);        //根据策略选一个        return doInvoke(invocation, invokers, loadbalance);    }          protected  List> list(Invocation invocation) throws RpcException {    List> invokers = directory.list(invocation);    return invokers;     }}

2. invoker生成代理对象

代理的知识点不用说了。

3. 客户端的invoker逻辑

Protocol#refer

主要看DubboProtocol的逻辑

public  Invoker refer(Class serviceType, URL url) throws RpcException {      // create rpc invoker.      DubboInvoker invoker = new DubboInvoker(serviceType, url, getClients(url), invokers);      invokers.add(invoker);      return invoker;}

DubboInvoker

底层调用netty通信api发送数据到客户端。然后读取数据。

客户端doInvoke时候会生成ExchangeClient就是NettyClient。public class DubboInvoker extends AbstractInvoker {    @Override    protected Result doInvoke(final Invocation invocation) throws Throwable {        RpcInvocation inv = (RpcInvocation) invocation;        final String methodName = RpcUtils.getMethodName(invocation);        inv.setAttachment(Constants.PATH_KEY, getUrl().getPath());        inv.setAttachment(Constants.VERSION_KEY, version);                ExchangeClient currentClient;        if (clients.length == 1) {            currentClient = clients[0];        } else {            currentClient = clients[index.getAndIncrement() % clients.length];        }        try {            boolean isAsync = RpcUtils.isAsync(getUrl(), invocation);            boolean isOneway = RpcUtils.isOneway(getUrl(), invocation);            int timeout = getUrl().getMethodParameter(methodName, Constants.TIMEOUT_KEY,Constants.DEFAULT_TIMEOUT);            if (isOneway) {            boolean isSent = getUrl().getMethodParameter(methodName, Constants.SENT_KEY, false);                currentClient.send(inv, isSent);                RpcContext.getContext().setFuture(null);                return new RpcResult();            } else if (isAsync) {            ResponseFuture future = currentClient.request(inv, timeout) ;                RpcContext.getContext().setFuture(new FutureAdapter(future));                return new RpcResult();            } else {            RpcContext.getContext().setFuture(null);                return (Result) currentClient.request(inv, timeout).get();            }        } catch (TimeoutException e) {            throw new RpcException(RpcException.TIMEOUT_EXCEPTION, "Invoke remote method timeout. method: " + invocation.getMethodName() + ", provider: " + getUrl() + ", cause: " + e.getMessage(), e);        } catch (RemotingException e) {            throw new RpcException(RpcException.NETWORK_EXCEPTION, "Failed to invoke remote method: " + invocation.getMethodName() + ", provider: " + getUrl() + ", cause: " + e.getMessage(), e);        }    }        @Override    public boolean isAvailable() {        if (!super.isAvailable())            return false;        for (ExchangeClient client : clients){            if (client.isConnected() && !client.hasAttribute(Constants.CHANNEL_ATTRIBUTE_READONLY_KEY)){                //cannot write == not Available ?                return true ;            }        }        return false;    }  }

三、总结

在前文的基础上,客户端的代码算是比较简单的。

回顾以下本文学习的知识点:

  • 主要是集群容错
  • 负载均衡、路由。
  • 客户端如何发送数据DubboInvoker

主要是利用代理来实现的。

最后求关注,求订阅,谢谢你的阅读!

客户连接多个服务端_Dubbo源码解析之客户端Consumer相关推荐

  1. JAVA毕业设计Vue.js网上书城管理系统设计与实现服务端计算机源码+lw文档+系统+调试部署+数据库

    JAVA毕业设计Vue.js网上书城管理系统设计与实现服务端计算机源码+lw文档+系统+调试部署+数据库 JAVA毕业设计Vue.js网上书城管理系统设计与实现服务端计算机源码+lw文档+系统+调试部 ...

  2. java开源即时通讯软件服务端openfire源码构建

    java开源即时通讯软件服务端openfire源码构建 本文使用最新的openfire主干代码为例,讲解了如何搭建一个openfire开源开发环境,正在实现自己写java聊天软件: 编译环境搭建 调试 ...

  3. php手游服务端开发教程,【手游服务端】梦想海贼王 卡牌系列一键端服务端游戏源码+教程...

    [手游服务端]梦想海贼王 卡牌系列一键端服务端游戏源码+教程 游戏介绍: <梦想海贼王>是一款卡牌类手游,游戏以全球第一超人气动漫<海贼王>为题材,用Q版风格配合新奇多样的玩法 ...

  4. C++RTSP服务端(附源码)

      VC++开发常用功能一系列文章 (欢迎订阅,持续更新...) 第16章:VC++ RTSP服务端(附源码)  源代码demo已上传到百度网盘:永久生效 ,文章尾部附 百度链接

  5. (Nacos源码解析五)Nacos服务事件变动源码解析

    Nacos源码解析系列目录 Nacos 源码编译运行 (Nacos源码解析一)Nacos 注册实例源码解析 (Nacos源码解析二)Nacos 服务发现源码解析 (Nacos源码解析三)Nacos 心 ...

  6. 客户连接多个服务端_Linux 服务端最大并发数是多少?

    (给Linux爱好者加星标,提升Linux技能) 转自:后端技术指南针 1. 开场白 在开始今天的文章之前,先抛一个面试题出来: 你接触过的单机最大并发数是多少? 你认为当前正常配置的服务器物理机最大 ...

  7. 暴露的全局方法_Dubbo源码解析实战 - 服务暴露原理

    欢迎关注全是干货的技术公众号 dubbo面试中比较喜欢问的两个点:服务发布和服务引用. 人性的拷问 服务发布过程中做了哪些事 dubbo都有哪些协议,他们之间有什么特点,缺省值是什么 什么是本地暴露和 ...

  8. 从零开始开发IM(即时通讯)服务端附源码

    前言 首先讲讲IM(即时通讯)技术可以用来做什么: 聊天:qq.微信 直播:斗鱼直播.抖音 实时位置共享.游戏多人互动等等 可以说几乎所有高实时性的应用场景都需要用到IM技术. 本篇将带大家从零开始搭 ...

  9. 热血传奇服务端FIR0918源码服务端Actor继承关系以及注解

    首先要声明一下,Fir0918服务端方面个人感觉实在是渣 代码各种乱入,写此博客只是记录自己学习的点滴.并不是来告诉大家fir的代码有多好. TBaseObject 只有四个成员 对象所在地图的X,Y ...

最新文章

  1. jira以及jira API简单介绍
  2. oracle技术之检查点及SCN深入研究
  3. 程序编译出错,缺少类型说明符;语法错误 : 缺少“;”(在标识符“PVOID64”的前面)
  4. SpringBoot+pagehelper分页之后还显示全部数据(分页不管用)的解决方案
  5. MongoDB自动删除过期数据--TTL索引
  6. 域服务器更改计算机名,Active Directory管理之:更改DC的IP地址与重命名DC计算机名...
  7. 强制apt使用ipv4来更新
  8. R金融统计:收益、随机行走和模拟
  9. ECharts 雷达图在类目值下面显示数值
  10. 设计模式_第二篇_策略模式
  11. matlab哈宁低通,Matlab实现电网谐波测量加窗插值算法.pdf
  12. 用curl访问HTTPS站点并登录
  13. Kafka Producer生产者原理
  14. 数字图像处理(四) 数字增强
  15. 图像patch feature源码
  16. 树莓派(0) : 树莓派4系统烧录、开机配置、网络连接、静态ip、开启root账号及ssh
  17. 使用MTK的SN writer工具写IMEI的方法
  18. 2022年最新用最简单粗暴的方式讲解:pytest简介,框架基础应用,运行方式,失败用例重跑。直击核心
  19. DeFi 入门必备:你需要了解的 DeFi 重要词语
  20. 仿网易新闻顶部菜单html,iOS仿网易新闻滚动导航条效果

热门文章

  1. OpenCASCADE:拓扑 API之对象修改
  2. wxWidgets:wxCondition类用法
  3. boost::distance用法的测试程序
  4. boost::histogram::make_weighted_histogram用法的测试程序
  5. boost::function_types::is_function_pointer用法的测试程序
  6. ITK:计算纹理特征
  7. OpenCV加载Caffe框架模型
  8. OpenGL textures combined组合纹理的实例
  9. C语言quaternion(四元数)(附完整源码)
  10. C++什么是内存泄漏