当进行远程跨进程服务调用时,需要把被传输的Java对象编码为字节数组或者ByteBuffer对象。而当远程服务读取到ByteBuffer对象或者字节数组时,需要将其解码为发送时的Java对象。这被称为Java对象编解码技术。而我们常见得Java序列化仅仅是Java编解码技术的一种,由于java序列化有以下缺点:
- 无法跨语言
- 序列化后的码流太大
- 序列化性能太低
因此衍生了多种编解码技术和框架。
如何评判一个编解码框架的优劣
- 是否支持跨语言,支持的语言种类是否丰富
- 编码后的码流大小
- 编解码的性能
- 类库是否小巧,API使用是否方便
- 使用者需要手工开发的工作量和难度
在同等情况下,编码后的字节数组越大,存储的时候就越占空间,存储的硬件成本就越高,并且在网络传输时更占带宽,导致系统的吞吐量降低。
业界主流的编解码框架
- Google的Protobuf
- Facebook的Thrift
- JBoss Marshalling
后面会介绍以上三个编解码框架的使用。
MessagePack编解码
MessagePack的特点:
- 编解码高效,性能高
- 序列化之后的码流小
- 支持跨语言
使用
如果是使用Maven开发,先添加依赖:
<dependencies>
...
<dependency>
<groupId>org.msgpack</groupId>
<artifactId>msgpack</artifactId>
<version>${msgpack.version}</version>
</dependency>
...
</dependencies>
api使用:
// Create serialize objects.
List<String> src = new ArrayList<String>();
src.add("msgpack");
src.add("kumofs");
src.add("viver");
MessagePack msgpack = new MessagePack();
// Serialize
byte[] raw = msgpack.write(src);
// Deserialize directly using a template
List<String> dst1 = msgpack.read(raw, Templates.tList(Templates.TString));
System.out.println(dst1.get(0));
System.out.println(dst1.get(1));
System.out.println(dst1.get(2));
在Netty中使用实践
编码器开发
编码器MsgpackEncoder继承MessageToByteEncoder,负责将Object类型的POJO对象编码为byte数组,然后写入到ByteBuf中。
package com.ph.Netty;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.MessageToByteEncoder;
import org.msgpack.MessagePack;
/**
* msg编码器
* Create by PH on 2018/11/7
*/
public cla