IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 网络协议 -> Dubbo源码解析-序列化的实现 -> 正文阅读

[网络协议]Dubbo源码解析-序列化的实现

前言:

前文中介绍了有关Dubbo协议的相关知识。Dubbo协议是Dubbo框架自定义的一种协议,类似于HTTP协议,也是一种应用层协议。

从Dubbo框架结构来看(参考:https://dubbo.apache.org/zh/docsv2.7/dev/design/),其位于如下位置:

?

服务消费者和提供者依据协议的模式来进行消息的发送和接收。

在消息发送的过程中,需要对消息体进行序列化操作,而Dubbo本身提供了多种序列化方式,本文就来简单了解下这些序列化方式。

1.获取序列化方式的入口

之前DubboCodec中我们有简单说明过,入口在以下位置:

public class ExchangeCodec extends TelnetCodec {
 
    // 发送数据之前进行编码操作
    public void encode(Channel channel, ChannelBuffer buffer, Object msg) throws IOException {
        if (msg instanceof Request) {
            // 关注点在这里
            encodeRequest(channel, buffer, (Request) msg);
        } else if (msg instanceof Response) {
            encodeResponse(channel, buffer, (Response) msg);
        } else {
            super.encode(channel, buffer, msg);
        }
    }
    
    protected void encodeRequest(Channel channel, ChannelBuffer buffer, Request req) throws IOException {
        // 在这里获取序列化方式
        Serialization serialization = getSerialization(channel);
        ...
    }
    
    protected Serialization getSerialization(Channel channel) {
        // 具体见1.1
        return CodecSupport.getSerialization(channel.getUrl());
    }
}

1.1 CodecSupport.getSerialization()?

public class CodecSupport {
    public static Serialization getSerialization(URL url) {
        return ExtensionLoader.getExtensionLoader(Serialization.class).getExtension(
                url.getParameter(Constants.SERIALIZATION_KEY, Constants.DEFAULT_REMOTING_SERIALIZATION));
    }
}

同样是通过SPI的方式来获取序列化方式。如果在url中没有配置的话,则默认是hessian2方式。

2.Dubbo的序列化方式

通过Serialization接口的实现类,我们可以看到Dubbo支持的序列化方式如下:

?

以上是常用的几种序列化方式,至于这些序列化方式的使用场景,在?成熟度 | Apache Dubbo? 中有说明

FeatureMaturityStrengthProblemAdviseUser
Hessian SerializationStable性能较好,多语言支持(推荐使用)Hessian的各版本兼容性不好,可能和应用使用的Hessian冲突,Dubbo内嵌了hessian3.2.1的源码可用于生产环境Alibaba
Dubbo SerializationTested通过不传送POJO的类元信息,在大量POJO传输时,性能较好当参数对象增加字段时,需外部文件声明试用
Json SerializationTested纯文本,可跨语言解析,缺省采用FastJson解析性能较差试用
Java SerializationStableJava原生支持性能较差可用于生产环境

而如果是纯java应用,则可以考虑使用性能更高的Kryo/FST序列化方式,在官网有关于其性能测试结果,具体在?Kryo 和 FST 序列化 | Apache Dubbo?

最终结果如下两张图:

?

?

由以上测试结果可以看到:Kryo/FST相对其他序列化方式有显著的改进。

3.序列化源码解析

序列化的方式有这么多种,笔者不一一介绍了,挑一个大家都比较熟悉的,说明一下序列化的过程即可。

那我们就选择JavaSerialization(JDK原生的序列化方式)来做说明

3.1 序列化的过程

首先我们从ExchangeCodec.java来看下序列化的过程,这样可以更针对性的学习序列化的相关实现

public class ExchangeCodec extends TelnetCodec {
    protected void encodeRequest(Channel channel, ChannelBuffer buffer, Request req) throws IOException {
        // 获取序列化实现方式
        Serialization serialization = getSerialization(channel);
        ...
        // 通过serialize()方法获取ObjectOutput对象
        ObjectOutput out = serialization.serialize(channel.getUrl(), bos);
        if (req.isEvent()) {
            encodeEventData(channel, out, req.getData());
        } else {
            // 序列化请求data
            encodeRequestData(channel, out, req.getData(), req.getVersion());
        }
        // 刷新缓存
        out.flushBuffer();
        ...
    }
    
    protected void encodeRequestData(Channel channel, ObjectOutput out, Object data, String version) throws IOException {
        encodeRequestData(out, data);
    }
    
    protected void encodeRequestData(ObjectOutput out, Object data) throws IOException {
        // 最终通过调用ObjectOutput.writeObject()方法来实现序列化
        out.writeObject(data);
    }
}

通过分析可知:序列化的过程主要分为以下几个步骤:

* 获取序列化实现方式Serialization

* 通过Serialization.serialize() 方法获取ObjectOutput对象,后续都是通过ObjectOutput来操作

* 通过ObjectOutput.writeObject() 实现对请求对象的序列化

* 刷新ObjectOutput

通过以上序列化过程,我们参照JavaSerialization来观察其实现。

3.2?JavaSerialization

public class JavaSerialization implements Serialization {
	// Constants.java中定义  byte JAVA_SERIALIZATION_ID = 3;
    public byte getContentTypeId() {
        return JAVA_SERIALIZATION_ID;
    }

    @Override
    public String getContentType() {
        return "x-application/java";
    }

    // 获取ObjectOutput对象
    public ObjectOutput serialize(URL url, OutputStream out) throws IOException {
        return new JavaObjectOutput(out);
    }

    @Override
    public ObjectInput deserialize(URL url, InputStream is) throws IOException {
        return new JavaObjectInput(is);
    }
}

JavaSerialization中所使用的ObjectOutput实现类为JavaObjectOutput,后续的序列化操作都交由JavaObjectOutput来实现

3.2.1 JavaObjectOutput的使用

public class JavaObjectOutput extends NativeJavaObjectOutput {
    public JavaObjectOutput(OutputStream os) throws IOException {
        // 创建一个JDK原声的ObjectOutputStream对象,用于序列化对象
        super(new ObjectOutputStream(os));
    }

    public JavaObjectOutput(OutputStream os, boolean compact) throws IOException {
        super(compact ? new CompactedObjectOutputStream(os) : new ObjectOutputStream(os));
    }

    @Override
    public void writeUTF(String v) throws IOException {
        if (v == null) {
            getObjectOutputStream().writeInt(-1);
        } else {
            getObjectOutputStream().writeInt(v.length());
            getObjectOutputStream().writeUTF(v);
        }
    }

    // 主要看这个方法
    public void writeObject(Object obj) throws IOException {
        if (obj == null) {
            getObjectOutputStream().writeByte(0);
        } else {
            // 本质上直接调用了ObjectOutputStream.writeObject()方法
            getObjectOutputStream().writeByte(1);
            getObjectOutputStream().writeObject(obj);
        }
    }

    @Override
    public void flushBuffer() throws IOException {
        // 直接调用ObjectOutputStream.flush()进行刷新
        getObjectOutputStream().flush();
    }
}

总结:

JavaSerialization的实现并不算复杂,本质上,所有的序列化操作都交由JDK原声的ObjectOutputStream来执行。

而其他的序列化方式也是类似的,通过Serialization提供一个标准模板,具体的序列化操作都交由具体的实现来完成即可。

  网络协议 最新文章
使用Easyswoole 搭建简单的Websoket服务
常见的数据通信方式有哪些?
Openssl 1024bit RSA算法---公私钥获取和处
HTTPS协议的密钥交换流程
《小白WEB安全入门》03. 漏洞篇
HttpRunner4.x 安装与使用
2021-07-04
手写RPC学习笔记
K8S高可用版本部署
mySQL计算IP地址范围
上一篇文章      下一篇文章      查看所有文章
加:2021-12-10 11:24:18  更:2021-12-10 11:26:41 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/26 10:33:32-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码