Java|几种Java常用序列化框架的选型与对比( 三 )


3Kryo序列化框架
Kryo一个快速有效的Java二进制序列化框架 , 它依赖底层ASM库用于字节码生成 , 因此有比较好的运行速度 。 Kryo的目标就是提供一个序列化速度快、结果体积小、API简单易用的序列化框架 。 Kryo支持自动深/浅拷贝 , 它是直接通过对象->对象的深度拷贝 , 而不是对象->字节->对象的过程 。
下面是使用Kryo进行序列化的Demo:
privatestatic final ThreadLocal<Kryo> kryoLocal = ThreadLocal.withInitial(() -> {Kryo kryo = new Kryo();kryo.setRegistrationRequired(false);//不需要提前预注册类return kryo;);
publicstaticbyte[
encoder(Object object) {Output output = new Output();kryoLocal.get().writeObject(outputobject);output.flush();return output.toBytes();
publicstatic <T> T decoder(byte[
bytes) {Input input = new Input(bytes);Object ob = kryoLocal.get().readClassAndObject(input);return (T) ob;
需要注意的是使用Output.writeXxx时候一定要用对应的Input.readxxx , 比如Output.writeClassAndObject()要与Input.readClassAndObject() 。
通用性
首先Kryo官网说自己是一款Java二进制序列化框架 , 其次在网上搜了一遍没有看到Kryo的跨语言使用 , 只是一些文章提及了跨语言使用非常复杂 , 但是没有找到其它语言的相关实现 。
易用性
在使用方式上Kryo提供的API也是非常简洁易用 , Input和Output封装了你几乎能够想到的所有流操作 。 Kryo提供了丰富的灵活配置 , 比如自定义序列化器、设置默认序列化器等等 , 这些配置使用起来还是比较费劲的 。
可扩展性
Kryo默认序列化器FiledSerializer是不支持字段扩展的 , 如果想要使用扩展序列化器则需要配置其它默认序列化器 。
比如:
privatestaticfinal ThreadLocal<Kryo> kryoLocal = ThreadLocal.withInitial(() -> {Kryo kryo = new Kryo();kryo.setRegistrationRequired(false);kryo.setDefaultSerializer(TaggedFieldSerializer.class);return kryo;);
性能
使用Kryo测试上面的测试用例 , Kryo序列化后的字节大小为172, 和FST未经优化的大小一致 。 时间开销如下:
我们同样关闭循环引用配置和预注册序列化类 , 序列化后的字节大小为120 , 因为这时候类序列化的标识是使用的数字 , 而不是类全名 。 使用的是时间开销如下:
数据类型和语法结构支持性
Kryo对于序列化类的基本要求就是需要含有无参构造函数 , 因为反序列化过程中需要使用无参构造函数创建对象 。
4Protocol buffer
Protocol buffer是一种语言中立、平台无关、可扩展的序列化框架 。 Protocol buffer相较于前面几种序列化框架而言 , 它是需要预先定义Schema的 。
下面是使用Protobuf的Demo:
(1)编写proto描述文件:
syntax = \"proto3\";
option java_package = \"com.yjz.serialization.protobuf3\";
message MessageInfo{string username = 1;string password = 2;int32 age = 3;map<stringstring> params = 4;
(2)生成Java代码:
protoc --java_out=./src/main/java message.proto
(3)生成的Java代码 , 已经自带了编解码方法:
//编码byte[
bytes = MessageInfo.toByteArray()//解码MessageInfo messageInfo = Message.MessageInfo.parseFrom(bytes);
通用性
protobuf设计之初的目标就是能够设计一款与语言无关的序列化框架 , 它目前支持了Java、Python、C++、Go、C#等 , 并且很多其它语言都提供了第三方包 。 所以在通用性上 , protobuf是非常给力的 。
易用性
protobuf需要使用IDL来定义Schema描述文件 , 定义完描述文件后 , 我们可以直接使用protoc来直接生成序列化与反序列化代码 。 所以 , 在使用上只需要简单编写描述文件 , 就可以使用protobuf了 。
可扩展性
可扩展性同样是protobuf设计之初的目标之一 , 我们可以非常轻松的在.proto文件进行修改 。
新增字段:对于新增字段 , 我们一定要保证新增字段要有对应的默认值 , 这样才能够与旧代码交互 。 相应的新协议生成的消息 , 可以被旧协议解析 。
删除字段:删除字段需要注意的是 , 对应的字段、标签不能够在后续更新中使用 。 为了避免错误 , 我们可以通过reserved规避带哦 。
message userinfo{reserved 37;//在保留标签中 , 添加删除的字段标签reserved \"age\"\"sex\"//在保留字段中 , 添加删除的字段
protobuf在数据兼容性上也非常友好 , int32、unit32、int64、unit64、bool是完全兼容的 , 所以我们可以根据需要修改其类型 。
通过上面来看 , protobuf在扩展性上做了很多 , 能够很友好的支持协议扩展 。
性能
我们同样使用上面的实例来进行性能测试 , 使用protobuf序列化后的字节大小为 192 , 下面是对应的时间开销 。