默认协议的rpc 过程是比较复杂的,其中涉及到了各个方面,其余各协议实际上有对这个过程进行简化;因此看懂了默认协议的rpc 过程,其他协议就非常容易懂了。在讲Dubbo通信过程之前,可以先了解:Java 远程通讯可选技术及原理

通信过程

我们可以通过如下7 点分析RPC 通信过程:

  • 是基于什么协议实现的?
  • 怎么发起请求?
  • 怎么将请求转化为符合协议的格式的?
  • 使用什么传输协议传输?
  • 响应端基于什么机制来接收请求?
  • 怎么将流还原为传输格式的?
  • 处理完毕后怎么回应?

此时我们用默认协议来分析:

  • 是基于什么协议实现的?

    Dubbo 协议(通信使用netty 协议)

  • 怎么发起请求?

    请求内容封装在RpcInvocation 对象,利用netty 客户端发请求

  • 怎么将请求转化为符合协议的格式的?

    对象序列化(其实还包含编码及解码过程)

  • 使用什么传输协议传输?

    Netty(本质是NIO 及socket)

  • 响应端基于什么机制来接收请求?

    Netty 的响应机制

  • 怎么将流还原为传输格式的?

    反序列化

  • 处理完毕后怎么回应?

    回应内容封装为RpcResult 对象中,序列化后通过netty 传给客户端

这个流程可以通过下图表示:

要了解这一过程,最好的方式就是在各处设置断点,然后在consumer端和provider端debug几次。

序列化

在了解Dubbo的序列化之前,需要先了解Java序列化的基本概念及原理:

序列化:dubbo提供了一系列的序列化反序列化对象工具。

Serialization接口定义:

/**
* Serialization. (SPI, Singleton, ThreadSafe)
*/
@SPI("hessian2")
public interface Serialization { /**
* get content type id
*
* @return content type id
*/
byte getContentTypeId(); /**
* get content type
*
* @return content type
*/
String getContentType(); /**
* create serializer
*
* @param url
* @param output
* @return serializer
* @throws IOException
*/
@Adaptive
ObjectOutput serialize(URL url, OutputStream output) throws IOException; /**
* create deserializer
*
* @param url
* @param input
* @return deserializer
* @throws IOException
*/
@Adaptive
ObjectInput deserialize(URL url, InputStream input) throws IOException; }

SPI注解指定了序列化的默认实现为hessian2。

Serialization依赖于JDK的OutputStream,InputStream,因为各具体的序列化工具依赖于OutputStream,InputStream。但为了屏蔽各个序列化接口对Dubbo侵入,Dubbo定义统一的DataOutput DataInput接口来适配各种序列化工具的输入输出。

我们用默认的序列化Hessian2Serialization来举例来说明

public class Hessian2Serialization implements Serialization {

    public static final byte ID = 2;

    public byte getContentTypeId() {
return ID;
} public String getContentType() {
return "x-application/hessian2";
} public ObjectOutput serialize(URL url, OutputStream out) throws IOException {
return new Hessian2ObjectOutput(out);
} public ObjectInput deserialize(URL url, InputStream is) throws IOException {
return new Hessian2ObjectInput(is);
} }

Hessian2Serialization构建基于Hessian的Dubbo 接口Output,Input实现, Dubbo是基于Output,Input接口操作不需要关心具体的序列化反序列化实现方式。

/**
* Hessian2 Object output.
*/
public class Hessian2ObjectOutput implements ObjectOutput {
private final Hessian2Output mH2o; public Hessian2ObjectOutput(OutputStream os) {
mH2o = new Hessian2Output(os);
mH2o.setSerializerFactory(Hessian2SerializerFactory.SERIALIZER_FACTORY);
} public void writeBool(boolean v) throws IOException {
mH2o.writeBoolean(v);
} public void writeByte(byte v) throws IOException {
mH2o.writeInt(v);
} public void writeShort(short v) throws IOException {
mH2o.writeInt(v);
} public void writeInt(int v) throws IOException {
mH2o.writeInt(v);
} public void writeLong(long v) throws IOException {
mH2o.writeLong(v);
} public void writeFloat(float v) throws IOException {
mH2o.writeDouble(v);
} public void writeDouble(double v) throws IOException {
mH2o.writeDouble(v);
} public void writeBytes(byte[] b) throws IOException {
mH2o.writeBytes(b);
} public void writeBytes(byte[] b, int off, int len) throws IOException {
mH2o.writeBytes(b, off, len);
} public void writeUTF(String v) throws IOException {
mH2o.writeString(v);
} public void writeObject(Object obj) throws IOException {
mH2o.writeObject(obj);
} public void flushBuffer() throws IOException {
mH2o.flushBuffer();
}
}

Hessian2ObjectInput读取Hessian序列化的数据使用方式同上面类似就不再贴代码了请自己翻看源代码。

实际上:1)序列化:读取对象字段,按照一定格式写入文件(当然也可以使其他媒介);2)反序列化:利用反射机制生成类对象,从媒介中读取对象信息,将这些字段信息赋给对象。

Encode和Decode

在dubbo协议的传输过程中,client并非只是单纯将RpcInvocation对象序列化后传递给server,同理server也不是将RpcResult对象反序列化后传递给client;其中涉及到编解码的过程。

这里我们看到NettyClient.java代码中(NettyServer.java也有类似):

    @Override
protected void doOpen() throws Throwable {
NettyHelper.setNettyLoggerFactory();
bootstrap = new ClientBootstrap(channelFactory);
// config
// @see org.jboss.netty.channel.socket.SocketChannelConfig
bootstrap.setOption("keepAlive", true);
bootstrap.setOption("tcpNoDelay", true);
bootstrap.setOption("connectTimeoutMillis", getTimeout());
final NettyHandler nettyHandler = new NettyHandler(getUrl(), this);
bootstrap.setPipelineFactory(new ChannelPipelineFactory() {
public ChannelPipeline getPipeline() {
NettyCodecAdapter adapter = new NettyCodecAdapter(getCodec(), getUrl(), NettyClient.this);
ChannelPipeline pipeline = Channels.pipeline();
pipeline.addLast("decoder", adapter.getDecoder());
pipeline.addLast("encoder", adapter.getEncoder());
pipeline.addLast("handler", nettyHandler);
return pipeline;
}
});
}

这里实际上是netty机制中会对channle中的内容进行编解码。

而我们看NettyCodecAdapter中,实际上处理编解码的是Codec2,这是一个接口,其具体的类在META-INF/dubbo/internal/com.alibaba.dubbo.remoting.Codec2文件中定义:

dubbo=com.alibaba.dubbo.rpc.protocol.dubbo.DubboCountCodec

最后真正做编解码任务的是DubboCodec,除了对RpcInvocation和RpcResult序列化或者反序列化外,还会加入一些其他信息。

Dubbo实践(十一)远程调用流程的更多相关文章

  1. dubbo支持的远程调用方式

    dubbo RPC(二进制序列化 + tcp协议).http invoker(二进制序列化 + http协议,至少在开源版本没发现对文本序列化的支持).hessian(二进制序列化 + http协议) ...

  2. 架构师之路-在Dubbo中开发REST风格的远程调用

    架构师之路:从无到有搭建中小型互联网公司后台服务架构与运维架构 http://www.roncoo.com/course/view/ae1dbb70496349d3a8899b6c68f7d10b 概 ...

  3. 【Rest】在Dubbo中开发REST风格的远程调用(RESTful Remoting)

    目录 概述 REST的优点 应用场景 快速入门 标准Java REST API:JAX-RS简介 REST服务提供端详解 HTTP POST/GET的实现 Annotation放在接口类还是实现类 J ...

  4. SpringBoot&Dubbo&Zookeeper远程调用项目搭建

    序言 Dubbo一款分布式服务框架,作为阿里巴巴SOA服务化治理方案的核心框架,通过高性能和透明化的RPC实现服务的远程调用,对服务的负载均衡以及项目的耦合性提供很强的解决方式;具体Dubbo的介绍和 ...

  5. Dubbo如何支持本地调用?injvm方式解析

    Dubbo是一个远程调用的框架,对于一个服务提供者,暴露了一个接口供外部消费者调用,那么对于提供者自己是否可以调用这个接口,需要什么特殊处理吗? 这篇文章就分享下Dubbo关于本地调用的实现机制,以及 ...

  6. SpringBoot2.0 整合 Dubbo框架 ,实现RPC服务远程调用

    一.Dubbo框架简介 1.框架依赖 图例说明: 1)图中小方块 Protocol, Cluster, Proxy, Service, Container, Registry, Monitor 代表层 ...

  7. Spring Boot 2 整合 Dubbo 框架 ,实现 RPC 服务远程调用

    一.Dubbo框架简介 1.框架依赖   图例说明: 1)图中小方块 Protocol, Cluster, Proxy, Service, Container, Registry, Monitor 代 ...

  8. Dubbo搭建HelloWorld-搭建服务提供者与服务消费者并完成远程调用(附代码下载)

    场景 Dubbo简介与基本概念: https://blog.csdn.net/BADAO_LIUMANG_QIZHI/article/details/103555224 Dubbo环境搭建-ZooKe ...

  9. 架构设计:一种远程调用服务的设计构思(zookeeper的一种应用实践)

    在深入学习zookeeper我想先给大家介绍一个和zookeeper相关的应用实例,我把这个实例命名为远程调用服务.通过对这种应用实例的描述,我们会对zookeeper应用场景会有深入的了解. 远程调 ...

随机推荐

  1. python保存字典和读取字典pickle

    import pickle import numpy as np def save_obj(obj, name): with open(name + '.pkl', 'wb') as f: pickl ...

  2. border实现三角形的原理

    前言:网上最普遍的实现三角形的方法,就是通过控制border来实现,那为什么可以呢? 原理 我们先来看看border的表现形式. #box{ width:100px; height:100px; ba ...

  3. Akka - Basis for Distributed Computing

    Some concepts as blow: Welcome to Akka, a set of open-source libraries for designing scalable, resil ...

  4. 用Java开发贪吃蛇游戏

    贪吃蛇游戏的设计步骤: Part 1: 设计游戏图纸 画出900*700的白色窗口 在窗口上添加画布 在画布上添加标题 在画布上添加黑色游戏区 Part 2: 放置静态的蛇:一个头.两个身体 加上开始 ...

  5. Android Weekly Notes Issue #247

    Android Weekly Issue #247 March 5th, 2017 Android Weekly Issue #247. 本期内容包括: 离线模式的实现; RxJava2的测试支持; ...

  6. MUI框架-06-静态页制作(图片轮播)

    MUI框架-06-静态页制作(图片轮播) 轮播也是静态,是相对页面交互来说 上一篇介绍了如何设计一个简单的界面,还没有接触过,请先查看: MUI框架-01-介绍-创建项目-简单页面 轮播组件 之前也介 ...

  7. ESP8266调试记录

    1.引脚图:使用STM32F103ZET6芯片的串口1  PA9-TX //PA10-RX(该串口挂载到APB2总线时钟)然后分别连接模块的RX和TX,供电使用3.3v(供电一定要稳)但不能超过5v ...

  8. IT之路如何走得更远

    作者:石头2075链接:http://www.jianshu.com/p/8c6417e16505著作权归作者所有.商业转载请联系作者获得授权,非商业转载请注明出处. 首先,你需要在合适的年纪进入了这 ...

  9. C# winfrom Datagridview控件下拉菜单

    拖拽一个datagridview放在界面,编辑列把下来菜单那列ColumnType设置成DataGridViewComboBoxColumn 然后在数据一栏的Items可以写下来菜单的内容也可以后台代 ...

  10. ASP.net Substitution 页面缓存而部分不缓存的实现方法

    在ASP.NET中要实现部分内容非缓存,而其它的都需要缓存输出,可以使用Substitution控件实现. <%@ Page Language="C#" AutoEventW ...