什么是序列化和反序列化
序列化:将对象转成二进制进行传输或者持久化
反序列化:将二进制转成对象
常见的序列化工具
1. Java原生序列化 Serializable
只要让类实现 Serializable 接口就行,序列化具体的实现是由ObjectOutputStream和ObjectInputStream来实现的。
注意以下几个点:
1、serialVersionUID 一定要自己写,不要省略,不然会导致无法序列化或者修改之后报错
如下出现兼容性问题:
java.io.InvalidClassException: com.example.seriable.Student; local class incompatible: stream classdesc
serialVersionUID = -926212341182608815, local class serialVersionUID = -6840182814363029482
关于这个异常,它是属于兼容问题异常,是发生在反序列化阶段,检测到 serialVersionUID 不一致导致的。具体的分析如下
序列化时使用的 serialVersionUID = -926212341182608815L,如果期间属性被修改了,如果 serialVersionUID 发生改变 -6840182814363029482 ,那么反序列化时就会出现类不兼容问题。
VersionUid会发生如下三种的变化
- 手动去修改导致当前的 serialVersionUID 与序列化前的不一样。
- 我们根本就没有手动去写这个 serialVersionUID 常量,那么 JVM 内部会根据类结构去计算得到这个 serialVersionUID 值,在类结构发生改变时(属性增加,删除或者类型修改了)这种也是会导致 serialVersionUID 发生变化。
- 假如类结构没有发生改变,并且没有定义 serialVersionUID ,但是反序列和序列化操作的虚拟机不一样也可能导致计算出来的 serialVersionUID 不一样。
2、 静态变量和transient 标识的对象成员变量不参与序列化
静态变量属于类属性,序列化只针对实例属性进行序列化
缺点:
1:序列化码流太大
2:序列化效率低
3:无法跨语言
优点:
简单
2. JSON序列化
JSON 可能是我们最熟悉的一种序列化格式了,JSON 是典型的 Key-Value 方式,没有数据类型,是一种文本型序列化框架,JSON 的具体格式和特性,网上相关的资料非常多,这里就不再介绍了。他在应用上还是很广泛的,无论是前台 Web 用 Ajax 调用、用磁盘存储文本类型的数据,还是基于 HTTP 协议的 RPC 框架通信,都会选择 JSON 格式。
实际应用场景:前端用请求头传来数据,我们机型json反序列化
常见的序列化包jackson和fastjson(不建议使用,有bug)
缺点:
- JSON进行序列化的额外空间开销比较大,对于大数据量服务就意味着需要巨大的内存和磁盘开销。
- JSON没有类型,但像Java这种强类型语言,需要通过反射统一解决,所以性能不会太好。
优点:
简洁明了
3. Hessian
Hessian 是动态类型、二进制、紧凑的,并且可跨语言移植的一种序列化框架。Hessian 协议要比 JDK、JSON 更加紧凑,性能上要比 JDK、JSON 序列化高效很多,而且生成的字节数也更小
Student student = new Student();
student.setNo(101);
student.setName("HESSIAN");
//把student对象转化为byte数组
ByteArrayOutputStream bos = new ByteArrayOutputStream();
Hessian2Output output = new Hessian2Output(bos);
output.writeObject(student);
output.flushBuffer();
byte[] data = bos.toByteArray();
bos.close();
//把刚才序列化出来的byte数组转化为student对象
ByteArrayInputStream bis = new ByteArrayInputStream(data);
Hessian2Input input = new Hessian2Input(bis);
Student deStudent = (Student) input.readObject();
input.close();
System.out.println(deStudent);
缺点:
- 官方版本对Java里面一些常见对象的类型不支持,比如LinkedHashMap、LinkedHashSet 等,但是可以通过扩展CollectionDeserializer 类修复,Locale 类,可以通过扩展 ContextSerializerFactory 类修复;
- Byte/Short 反序列化的时候变成 Integer
优点:
- 相对于JDK,JSON,更加高效,生成的字节数更小
- 有非常好的兼容性和稳定性
4. Protobuf
Protobuf 是 Google 公司内部的混合语言数据标准,是一种轻便、高效的结构化数据存储格式,可以用于结构化数据序列化,支持 Java、Python、C++、Go 等语言。Protobuf使用的时候需要定义 IDL(Interface description language),然后使用不同语言的 IDL编译器,生成序列化工具类
缺点:
-
为了提高性能,protobuf采用了二进制格式进行编码。这直接导致了可读性差
-
对于具有反射和动态语言来讲,用起来比较费劲
优点: -
高效
-
支持多种语言
-
支持向前,向后兼容
首先自己定义proto文件,编码自己要进行序列化的类,然后使用编译器生成java类,使用类中的函数进行序列化和反序列化
详细参考Protobuf
5. Thrift
Thrift是Facebook于2007年开发的跨语言的rpc服框架,提供多语言的编译功能,并提供多种服务器工作模式,用户通过Thrift的IDL(接口定义语言)来描述接口函数及数据类型,然后通过Thrift的编译环境生成各种语言类型的接口文件,用户可以根据自己的需要采用不同的语言开发客户端代码和服务器端代码。
缺点:
- 没有官方文档
- Thrift序列化二进制不可读,调试困难
- buf fix 和更新不积极,维护成本过高
- RPC 在 0.6.1 升级到 0.7.0 是不兼容的
优点:
- 特性丰富.
- 性能不错
- 有很多开源项目的周边支持 都是 thrift