默认协议的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. 【SSH网上商城项目实战08】查询和删除商品类别功能的实现

    转自:https://blog.csdn.net/eson_15/article/details/51338991 上一节我们完成了使用DataGrid显示所有商品信息,这节我们开始添加几个功能:添加 ...

  2. IDEA 如何加上 tomcat

    前言: idea 上已经有一个 tomcat 了,因为这个 tomcat 为 32 的,需要加一个 64 为的 tomcat . 第一步: 第二步: 第三步: 点击 OK 就好. 结果:

  3. json的省市联动

    1 <%@ page contentType="text/html;charset=UTF-8" language="java" %> 2 < ...

  4. idea新建maven多模块spring boot项目

    1.新建一个maven多模块项目,比如这种结构: maven-demo |--demo-common |--demo-order |--demo-user 2.先新建一个maven项目,在maven项 ...

  5. csharp:A Custom CheckedListBox with Datasource

    /// <summary> /// (eraghi) /// Custom CheckedListBox with binding facilities (Value property) ...

  6. 停课+2week

    可真是,累啊. 本以为停课之后会轻松一点,结果天天好累的说... 今天开始得去锻炼锻炼了... 已经好几次突然一阵晕眩了qwq... 希望我还能挺得住吧,至少要挺到WC结束啊... 这次,可是关系到我 ...

  7. luogu P3065 first——trie树相关

    题目描述 Bessie has been playing with strings again. She found that by changing the order of the alphabe ...

  8. HTML5 Canvas中绘制椭圆的几种方法

    1.canvas自带的绘制椭圆的方法 ellipse(x, y, radiusX, radiusY, rotation, startAngle, endAngle, anticlockwise)是后来 ...

  9. GDAL线面互转换

    最近因为项目需要,需做GDAL线面互转的功能,查阅部分资料完成,下面把核心部分的代码贴出来,留个记录,也欢迎大家提问题指正完善. /* * @brief ConvertPolygonToPolylin ...

  10. 修改zabbix为中文,并解决乱码问题(三)

    当Zabbix安装完成后,默认则是英文界面,有的人看英文不习惯,现在将其改为中文界面 一.修改为中文 1.打开Zabbix界面,Administrator-Users 选择语言-Chinese(zh_ ...