4.2 常用序列化框架

4.2.1 Java默认序列化

Java序列化是在JDK 1.1中引入的,是Java内核的重要特性之一。如果希望一个类对象是可序列化的,所要做的就是实现Serializable接口。Serializable是一个标记接口,不需要实现任何字段和方法。这就像是一种选择性加入的处理,通过它可以使类对象成为可序列化的对象。序列化处理是通过ObjectInputStream和ObjectOutputStream实现的,因此我们所要做的是基于它们进行一层封装,要么将其保存为文件,要么将其通过网络发送。我们来看一个简单的序列化示例。

步骤01 定义AyUser对象,并实现Serializable接口,具体代码如下所示:

步骤02 自定义序列化接口ISerializer,具体代码如下所示:

步骤03 实现序列化接口ISerializer,同时实现serialize、deserialize、serializeToFile和deserializeFromFile方法,具体代码如下所示:

步骤04 开发测试程序,具体代码如下所示:

运行main方法,将在控制台打印如下信息,同时可以在项目下找到tmp.out文件。

打开项目下的tmp.out文件,文件内容如图4-1所示。

图4-1 tmp.out文件内容

这里对tpm.out文件进行简单分析,具体如下:

第一部分:序列化文件头

AC ED:STREAM_MAGIC,声明使用了序列化协议。

00 05:STREAM_VERSION,序列化协议版本。

73:TC_OBJECT,声明这是一个新的对象。

第二部分:序列化的类的描述

72:TC_CLASSDESC,声明这里开始一个新Class。

00 1D:Class名字的长度为29。

63 6F 6D 2E … 73 65 72:AyUser,Class类名。

62 AE F9 09 05 48 6F FB:SerialVersionUID,序列化ID,如果没有指定,就会由算法随机生成一个8字节的ID。

02:标记号,该值声明该对象支持序列化。

00 02:该类所包含的域个数。

第三部分:对象中各个属性的描述

4C:域类型:Long。

00 02:域名字的长度。

69 64 74 00 10 4C 6A:id,域名字描述。

第四部分:对象的父类信息描述

Serializable没有父类,如果有,就和第二部分的描述相同。

78:TC_ENDBLOCKDATA,对象块结束的标志。

70:TC_NULL,说明没有其他超类的标志。

第五部分:对象属性的实际值

这里只是简单分析JDK默认序列化协议,读者可以在网络上参考更多资料。

Java默认的序列化机制缺点很明显:

(1)只支持Java语言,不支持其他语言。

(2)性能差,序列化后的码流大,对于引用过深的对象序列化容易引起OOM异常。

4.2.2 XML序列化框架

XML序列化使用标签表示数据,可读性高。但是序列化后码流较大,性能不高,适用于性能不高且QPS较低的企业级内部系统之间数据交换的场景。XML具有语言无关性,可用于异构系统间的数据交换协议。XML序列化和反序列化实现方式有多种,比如XStream和Java自带的XML序列化和反序列化方式等。我们主要讲解Java自带的XML序列化和反序列化方式,其他的方式读者可自己查资料学习。

Java自带的XML序列化和反序列化主要使用XMLEncoder和XMLDecoder类实现相应的功能,具体实例如下所示:

上述代码开发完成之后,运行main函数,将可以在控制台看到如下打印信息:

     id :1
     name :ay

同时,在项目的目录下会生成ayUser.xml文件,文件内容如下所示:

下面我们简单封装XML序列化类XMLSerializer供读者参考,具体代码如下所示:

4.2.3 JSON序列化框架

JSON(JavaScript Object Notation,JS对象简谱)是一种轻量级的数据交换格式。JSON可以支持任何数据类型,例如字符串、数字、对象、数组等。相对于XML,JSON码流更小,而且还保留了XML可读性好的优势。

JSON序列化常用的开源工具有Fastjson(阿里巴巴开源)、Jackson和Google开发的GSON。从性能角度来看,Jackson和Fastjson比GSON的性能好。从稳定性来看,Jackson、GSON相对Fastjson稳定性更好。

接下来,我们重点介绍Fastjson序列化框架,该框架的主要优点有:

  • Fastjson具有极快的性能。
  • 功能强大,完全支持Java Bean、集合、Map、日期、Enum,同时支持泛型、支持自省等。
  • 无依赖,能够直接运行在Java SE 5.0以上版本。
  • 易用的API操作。

使用Fastjson进行序列化和反序列化非常简单,具体步骤如下所示。

步骤01 添加Fastjson依赖包,具体代码如下所示:

步骤02 开发序列化类JsonSerializer,简单封装序列化和反序列化接口:

4.2.4 ProtoBuf序列化框架

Google Protocol Buffer(简称ProtoBuf)是一种轻便高效的结构化数据存储格式,与平台无关、与语言无关、可扩展,可用于通信协议和数据存储等领域。

ProtoBuf高性能解析且码流小,非常适合性能要求高的RPC调用。但是使用ProtoBuf需要编写.proto IDL文件,开发工作量稍大,且需要额外学习Proto IDL特有的语法。

下面我们开始学习如何使用ProtoBuf序列化框架实现对象的序列化和反序列化,具体步骤如下:

步骤01 下载ProtoBuf安装包,例如protobuf-all-3.6.1.tar。

步骤02 在终端执行解压命令:

     ### 解压protobuf-all-3.6.1.tar
     tar zxvf protobuf-all-3.6.1.tar

步骤03 在解压后的目录protobuf-3.6.1下执行命令:

步骤04 执行protoc --version命令检查是否安装成功,如果输出如下信息,就代表ProtoBuf安装成功。

     ### 安装成功输出结果
     libprotoc 3.6.1

ProtoBuf安装成功之后,紧接着学习如何使用ProtoBuf,具体步骤如下所示。

步骤01 创建用户类AyUser,具体代码如下所示:

步骤02 编写AyUser.proto文件,具体代码如下所示:

  • syntax= "proto3":指定正在使用Proto 3语法,如果没有指定编译器,就默认使用Proto 2。
  • option java_package:表示自动生成代码时,将Java代码放入指定的package中。
  • java_outer_classname:表示生成的Java类的名称。
  • message:表示声明一个“类”,类似Java中的class。message中可以内嵌message,就像Java的内部类一样。一个message可以包含多个字段。ProtoBuf字段支持的数据类型如表4-1所示。

表4-1 ProtoBuf字段支持的类型汇总

步骤03 执行如下命令,生成相关的序列化工具类:

  • java_out指定生成Java代码保存的目录,后面紧跟.proto文件的路径。

注 意


该命令需要在项目的java目录下执行。

我们还可以在终端输入protoc --help命令查看protoc命令更多信息,具体代码如下所示:

步骤04 开发代码,将AyUser对象进行序列化和反序列化:

代码开发完成之后,运行main方法,便可以在控制台打印相关的信息。至此,使用ProtoBuf进行对象序列化和反序列化已完成,更多ProtoBuf相关的内容,读者可自主学习。