默认协议的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. String拾遗

    简介: String作为日常最常用的类,还是有必要对其中的细节做一些了解的,这篇就结合源码来看看这个常用的类. 一. 总述 类图如下: 从图中可以看到String是实现了 java.io.Serial ...

  2. mysql中LOCATE和CASE WHEN...THEN...ELSE...END结合用法

    之前项目中需要写一个sql,就是查出某个调研详情中,选A答案,B答案,C答案...F答案的人各有多少人,这个sql也是费了很大的力气才写出来,故记下来,方便以后使用. 其中tbl_research_i ...

  3. eslint规则记录

    "off"或者0 //关闭规则关闭 "warn"或者1 //在打开的规则作为警告(不影响退出代码) "error"或者2 //把规则作为一个 ...

  4. Class.forName和ClassLoader.loadClass的区别(转载)

    Class的装载分了三个阶段,loading,linking和initializing,分别定义在The Java Language Specification的12.2,12.3和12.4.Clas ...

  5. HTML5-入门。

    什么是HTML5? HTML5是超文本语言,不是编程语言,html5是html语言的最新版本,需要注意浏览器的兼容性问题. HTML5技术一般是指的是HTML5.CSS3.JavaScript三种技术 ...

  6. ExpressRoute 常见问题

    什么是 ExpressRoute? ExpressRoute 是一项 Azure 服务,允许在 Microsoft 数据中心与本地环境或共同租用设施中的基础结构之间创建专用连接. ExpressRou ...

  7. 一分钟在云端快速创建MySQL数据库实例

    本教程将帮助您了解如何使用Azure管理门户迅速创建,连接,配置MySQL 数据库 on Azure.完成本教程后,您将在Azure上拥有一个示例MySQL数据库服务器,并了解如何使用管理门户执行基本 ...

  8. 在datagridview中添加button按钮

    .Net的DataGridView控件中,提供了一种列的类型,叫 DataGridViewButtonColumn ,这种列类型是展示为一个 按钮,可以给button赋予相应的text,并且,此but ...

  9. SQL Server Mobile/Compact Edition 简单介绍

    除了SQL Server Express,SQL Server还有个更轻量级的版本:SQL Server Compact Edition,容易让人想起Windows Compact Edition ( ...

  10. maven将依赖的包一起打包

    把以下内容输入到pom中即可 <build> <plugins> <!-- 将项目的依赖包复制到 target/lib --> <plugin> < ...