Netty笔记1:线程模型
Netty笔记2:零拷贝
Netty笔记3:NIO编程
Netty笔记4:Epoll
Netty笔记5:Netty开发实例
Netty笔记6:Netty组件
Netty笔记7:ChannelPromise通知处理
Netty笔记8:ByteBuf使用介绍
Netty笔记9:粘包半包
Netty笔记10:LengthFieldBasedFrameDecoder
Netty笔记11:编解码器
Netty笔记12:模拟Web服务器
Netty笔记13:序列化
这里我只是搞了
MessagePack
和 Jackson
这两种,他们使用和性能上算是不错的。
在Java
中实现序列化只需要implements Serializable
,但是这种方式限定了Java
平台下,并且这种方式的性能也是很差的,不但内存占用高,消耗时间有长,具体的可以看这篇文章:几种Java常用序列化框架的选型与对比-阿里云开发者社区 (aliyun.com)
MessagePack(多语言支持)
MessagePack is a binary serialization format. If you need a fast and compact alternative of JSON, MessagePack is your friend. For example, a small integer can be encoded in a single byte, and short strings only need a single byte prefix + the original byte array. MessagePack implementation is already available in various languages (See also the list in http://msgpack.org) and works as a universal data format.
Message Pack specification: https://github.com/msgpack/msgpack/blob/master/spec.md
MessagePack v7 (or later) is a faster implementation of the previous version v06, and supports all of the message pack types, including extension format.
--->
MessagePack 是一种二进制序列化格式。如果你需要一个比 JSON 更快、更紧凑的替代方案,MessagePack 就是你的选择。例如,一个小整数可以仅用一个字节编码,短字符串只需要一个字节前缀加上原始字节数组。MessagePack 的实现已经存在于多种语言中(也可以参见列表),并且作为一个通用的数据格式工作。
MessagePack 规范:
MessagePack v7(或更高版本)是之前版本 v06 的更快实现,并支持所有 MessagePack 类型,包括扩展格式。
优点:
- 高效:节省空间;
- 跨语言:
MessagePack
支持多种语言; - 易于使用:序列化和反序列化调用API就行,不像有些框架需要些配置,编译等复杂操作;
缺点:
- 复杂数据类型支持不完善;
引入依赖,限制最新版本是0.9.8
<dependency>
<groupId>org.msgpack</groupId>
<artifactId>msgpack-core</artifactId>
<version>0.9.8</version>
</dependency>
发送端用
MessagePack
序列化public class MsgEncoder extends MessageToByteEncoder<UserInfo> { @Override protected void encode(ChannelHandlerContext ctx, UserInfo msg, ByteBuf out) throws Exception { ByteArrayOutputStream bos = new ByteArrayOutputStream(); try (MessagePacker mp = MessagePack.newDefaultPacker(bos);) { mp.packMapHeader(3); mp.packString("name").packString(msg.getName());; mp.packString("id").packInt(msg.getId()); mp.packString("data").packString(msg.getData()); // 设置完属性,记得调用这个方法将数据刷到bos mp.flush(); byte[] bytes = bos.toByteArray(); out.writeBytes(bytes); } } }
接收端用户
MessagePack
反序列化public class MsgDecoder extends ByteToMessageDecoder { @Override protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception { int length = in.readableBytes(); byte[] bytes = new byte[length]; in.readBytes(bytes);; try (MessageUnpacker mp = MessagePack.newDefaultUnpacker(bytes)) { ImmutableValue value = mp.unpackValue(); if (!value.isMapValue()) { throw new Exception("数据格式不对"); } Map<Value, Value> map = value.asMapValue().map(); String name = map.get(ValueFactory.newString("name")).asStringValue().asString(); int id = map.get(ValueFactory.newString("id")).asIntegerValue().asInt(); String data = map.get(ValueFactory.newString("data")).asStringValue().asString(); UserInfo info = new UserInfo(); info.setName(name); info.setId(id); info.setData(data); System.out.printf("读取到数据:name:%s, id:%d, data:%s%n", name, id, data); out.add(info); } } }
jackson
jackson
有官方提供的示例,建议去看看:msgpack-java/msgpack-jackson at main · msgpack/msgpack-java · GitHub
<dependency>
<groupId>org.msgpack</groupId>
<artifactId>jackson-dataformat-msgpack</artifactId>
<version>0.9.8</version>
</dependency>
需要注意:ObjectMapper
是线程安全的,这里示例为了读者清晰的思路写在一起了,实际开发中应该是全局配置或特殊配置的。
- 发送到编码器
public class MsgJacksonEncoder extends MessageToByteEncoder<UserInfo> {
@Override
protected void encode(ChannelHandlerContext ctx, UserInfo msg, ByteBuf out) throws Exception {
// 方法一
ObjectMapper objectMapper = new ObjectMapper(new MessagePackFactory());
byte[] bytes = objectMapper.writeValueAsBytes(msg);
out.writeBytes(bytes);
// 方法二
// ObjectMapper objectMapper2 = new MessagePackMapper();
// byte[] bytes2 = objectMapper2.writeValueAsBytes(msg);
// out.writeBytes(bytes2);
}
}
- 接收端解码器
public class MsgJacksonDecoder extends ByteToMessageDecoder {
@Override
protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception {
int length = in.readableBytes();
byte[] bytes = new byte[length];
in.readBytes(bytes);;
// 方法一
ObjectMapper objectMapper = new ObjectMapper(new MessagePackFactory());
// UserInfo info = objectMapper.readValue(bytes, UserInfo.class);
// System.out.println("读取到数据:" + JSON.toJSONString(info));
// 方法二
// ObjectMapper objectMapper2 = new MessagePackMapper();
// UserInfo info2 = objectMapper2.readValue(bytes, UserInfo.class);
// System.out.println("读取到数据:" + JSON.toJSONString(info2));
// 类型转换的另一种方式
TypeReference<UserInfo> typeReference = new TypeReference<UserInfo>(){};
UserInfo info3 = objectMapper.readValue(bytes, typeReference);
System.out.println("读取到数据:" + JSON.toJSONString(info3));
}
}
需要注意:ObjectMapper
是线程安全的,这里示例为了读者清晰的思路写在一起了,实际开发中应该是全局配置或特殊配置的。