默认协议的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 简单使用

    package com.direct.str; public class TestObject { /** * @param args */ /* * 1.object类是根类,里面定义的==和equ ...

  2. C# Task.FromResult的用法

    Task.FromResult用来创建一个带返回值的.已完成的Task. 场景一:以同步的方式实现一个异步接口方法比如有一个接口包含异步方法. interface IMyInterface { Tas ...

  3. html基础概念

    一.HyperText Markup Language   内容,html是弱代码语言,代码编写不严谨 1.超链接  <a href="#">超级链接(anchor)& ...

  4. Two references point to the same heap memory

    Phone类 package com.itheima_03; /* * 手机类 */ public class Phone { String brand; int price; String colo ...

  5. weex常用属性梳理

    之前发了一篇weex集成和开发的博客,主要是讲了weex开发环境的搭建和文件的编译.部署,还有就是一些个人对weex的理解,最近将原生的项目改造成weex的项目,也持续了有两个多月的时间了,后面我会发 ...

  6. 我只是个搬运工,walle

    安装 改进本文 walle 瓦力 自动化1.简洁安装指南 git clone git@github.com:meolu/walle-web.gitcd walle-webvi config/web.p ...

  7. faf

    1.Nginx的简单说明 a.  Nginx是一个高性能的HTTP和反向代理服务器,也是一个IMAP/POP3/SMTP服务器,期初开发的目的就是为了代理电子邮件服务器室友:Igor Sysoev开发 ...

  8. composer 应用【Modern PHP】

    目录 安装(linux) composer.lock 文件 composer.josn 文件 自动加载PHP组件 组件包库地址 实例 composer私有仓库 composer 遵循PSR准则,解决安 ...

  9. DNS配置范例

    这里使用CentOS 7作为DNS主服务器.(ip:172.18.7.77) 正向解析配置: ]# vim /etc/named.rfc1912.zones zone "opsnote.co ...

  10. Pip批量安装/卸载包

    pip批量安装package 将需要安装的包保存在requirements.txt中 cd到aa.txt所在目录,运行: pip install -r requirements.txt pip批量卸载 ...