序列化与反序列化

128 阅读5分钟

这是我参与8月更文挑战的第23天,活动详情查看: 8月更文挑战

在RPC通信中,发送放需要将数据序列后通过网络传输将数据传给接收方,这个时候接收方就需要对收到的数据进行反序列化操作,还原出具体的数据。JDK提供了Java对象的序列化实现对象序列化传输,主要通过ObjectOutputStream和ObjectInputStream来实现

  • ObjectOutputStream:表示对象输出流 , writeObject(Object obj)方法可以对参数指定的 obj 对象进行序列化,把得到的字节序列写到一个目标输出流中
  • ObjectInputStream:表示对象输入流 ,它的 readObject()方法源输入流中读取字节序列,再把它们反序列化成为一个对象,并将其返回

但是在使用序列化的时候需要实现 java.io.Serializable 接口,Java 的序列化机制是通过判断类的 serialVersionUID 来验证版本一致性的。在进行反序列化时,JVM 会把传来的字节流中的 serialVersionUID 与本地相应实体类的 serialVersionUID 进行比较,如果相同就认为是一致的,可以进行反序列化,否则就会出现序列化版本不一致的异常,即是 InvalidCastException。 对于对象数据序列话,在分布式架构下,很多都会采用RPC协议,对于序列化与反序列化就比较重要,java提供的序列化存在一定的问题:

  1. 序列化后的数据比较大,因为在序列化中带有类的相关信息,这样就导致传输效率低
  2. 序列化出来的数据只能够java语音反序列化,其他语音无法反序列化,不能夸语言使用

所以就有了其他的序列化技术

XML序列化

在最早的时候序列化都采用的是xml来实现的,主要是由于XML序列化的在于可读性好,方便阅读和调试。但是序列化以后的字节码文件比较大,而且效率不高,适用于对性能不高,而且 QPS 较低的企业级内部系统之间的数据交换的场景,同时 XML 又具有语言无关性,所以还可以用于异构系统之间的数据交换和协议。现在用的比较多的Webservice,就是采用 XML 格式对数据进行序列化的。XML 序列化/反序列化的实现方 式有很多,常用的方式有 XStream 和 Java 自带的 XML 序列化和反序列化两种

//对象序列化为XML
XStream xStream = new XStream(new DomDriver());
//设置对象别名
xStream.alias("student", Student.class);
//序列成xml字符串
String xml = xStream.toXML(student);

//反序列成对象
 Student student = (Student)xStream.fromXML(xml);

JSON序列化

JSON(JavaScript Object Notation)是一种轻量级的数据交换格式,相对于 XML 来说,JSON的字节流更小,而且可读性也非常好。现在JSON序列化也比较多,基本上提供API接口都采用JSON格式来提供,现在对于JSON序列化与反序列化技术也比较成功,常见的开源框架有: Jackson、FastJson、GSON。这几种JSON序列化工具中,Jackson 与 fastjson 要比 GSON 的性能要好,但是 Jackson、GSON 的稳定性要比 Fastjson 好。而 fastjson 的优势在于提供的 api 非常容易使用,国内用fastjson的比较多,API操作方便,文档中文版看起来很方便

//序列化  
String json = JSONObject.toJSONString(student);

//反序列化
Student student = JSONObject.parseObject(json, Student.class);

Hessian序列化

Hessian 是一个支持跨语言传输的二进制序列化协议,相对于 Java 默认的序列化机制来说,Hessian 具有更好的性能和易用性,而且支持多种不同的语言实际上 Dubbo 采用的就是 Hessian 序列化来实现,只不过 Dubbo 对 Hessian 进行了重构,性能更高

ByteArrayOutputStream os = new ByteArrayOutputStream();
Hessian2Output output = new Hessian2Output(os);
output.writeObject(student);

 ByteArrayInputStream bis = new ByteArrayInputStream(os.toByteArray());
Hessian2Input input = new Hessian2Input(bis);
Student student = (Student) input.readObject();

Avro序列化

Avro 是一个数据序列化系统,设计用于支持大批量数据交换的应用。它的主要特点有:支持二进制序列化方式,可以便捷,快速地处理大量数据;动态语言友好,Avro 提供的机制使动态语言可以方便地处理 Avro 数据

kyro序列化

Kryo 是一种非常成熟的序列化实现,已经在 Hive、Storm中使用得比较广泛,不过它不能跨语言. 目前 dubbo 已经在 2.6 版本支持 kyro 的序列化机制。它的性能要优于之前的hessian2

Protobuf序列化

Protobuf 是 Google 的一种数据交换格式,它独立于语言、独立于平台。Google 提供了多种语言来实现,比如 Java、C、Go、Python,每一种实现都包含了相应语言的编译器和库文件,Protobuf 是一个纯粹的表示层协议,可以和各种传输层协议一起使用。Protobuf 使用比较广泛,主要是空间开销小和性能比较好,非常适合用于公司内部对性能要求高的 RPC 调用。 另外由于解析性能比较高,序列化以后数据量相对较少,所以也可以应用在对象的持久化场景中 但是要使用 Protobuf 会相对来说麻烦些,因为他有自己的语法,有自己的编译器,如果需要用到的话必须要去投入成本在这个技术的学习中protobuf 有个缺点就是要传输的每一个类的结构都要生成对应的 proto 文件,如果某个类发生修改,还得重新生成该类对应的 proto 文件 使用 protobuf 开发的一般步骤是

    1. 配置开发环境,安装 protocol compiler 代码编译器
    1. 编写.proto 文件,定义序列化对象的数据结构
    1. 基于编写的.proto 文件,使用 protocol compiler 编译器生成对应的序列化/反序列化工具类
    1. 基于自动生成的代码,编写自己的序列化应用

对于不同的序列化框架都有各自的优缺点,至于在使用中,选用哪种框架,需要我们根据业务来选用具体的序列化框架,毕竟有失有得