序列化
最后更新于
这有帮助吗?
最后更新于
这有帮助吗?
在前面我们已经讲了,Java分布式通讯基于Socket,使用Socket通讯必须指定以下关键点:
IP
Port
通讯协议
其中很多通讯协议通常与RPC框架有关联,但是比较通用的,比如HTTP协议,这里就不再过多解释。关于通讯协议的部分,将会结合着RPC框架来进行讲解。本篇文章将会简单描述几种常用的序列化的使用方式,着重比较他们之间的序列化与反序列化效率。
通讯协议中不仅包含协议的内容,更是包含了我们通讯的数据。我们的数据在传输之前,位于Java代码中都是以JavaObject的形式表示的,因此这些数据在网络传输时,不可避免序列化、反序列化的过程。恰当的序列化方式不仅可以提高系统的性能,更是可以提高系统的安全性、通用性、强壮性,让系统易于调试和拓展。
Serializable
序列化结果大、传输效率低、不能跨语言对接
RMI
XML
通俗易懂、跨语言
序列化结果大、冗余标签多、传输效率低
WebService(SOAP)
JSON
通俗易懂、比起xml更精简,与js兼容好
序列化结果仍然很大、性能较低
HTTP Rest
Hessian
跨语言、紧凑的二进制协议、序列化速度快
序列化后的结果很大,大于Java序列化、可读性差
MessagePack
兼容 json 的数据格式、但是比JSON跟节省空间、支持多语言
序列化时间长大约是JSON的两倍
Protocol Buffer
吊打上面几个
需要预编译、安装 比较麻烦
Apache Thrift
与Protocol Buffers差不多、序列化时间要比Protocol Buffers短、反序列化时间要比PB长
Apache Avro
配置复杂
Kryo
针对Java的序列化系统
不跨语言
FST
针对Java的序列化系统
不跨语言
Serializable 是Java自带的序列化方式,速度慢,不跨语言,唯一的优点可能就是Java自带,不需要引入任何第三方扩展。Serializable
的序列化与发序列化需要借助ObjectInputStream
和ObjectOutputStream
,下面是代码演示:
凡是实现Serializable
接口的类,都需要声明 serialVersionUID
来标识序列化版本号。当使用版本号1进行序列化时,只能通过相同的版本号的类进行反序列化,否则就会抛出java.io.InvalidClassException
。以此保证序列化类型与反序列化类型是同一类型。
如果未指定serialiVersionUID
,Java 编译器会自动对类进行摘要算法生成一个serialVersionUID
,所以只要目标Java类有任何变动,得到的结果就会截然不同。
序列化并不保存静态变量的状态,所以序列化时静态变量 a
的值为2,那么反序列化时a的值不见的就是2,他的值仍然是 类.a
的值
如果想要某个属性不参与序列化,可以给这个属性加上transient
关键字。
如果父类没有实现序列化接口、子类实现了序列化接口,那么父类中的属性无法参与序列化
如果父类实现了序列化接口,子类没有实现,子类继承父类,所以父子类属性都会参与序列化
假设将Person p
对象序列化写入到文件p.bak
中,第一次假设耗费15ms的时间写入到了磁盘中,那么第二次写入同样的p对象,此时Java发现磁盘中已经存在此序列化文件,那么Java不会覆盖文件,而是在文件尾部添加了5个字节的引用关系,从而提高了重复对象的写入效率。下面是代码示例:
使用Java Serializable 还可以实现深克隆,只需要保证要克隆的对象以及属性都实现了Serializable接口即可,复制出的对象与原有对象是两个对象。代码这里不再演示。
JSON序列化方式是Java应用程序中最为常用的序列化方式,与Javascript有较好的兼容性,最典型的就是用在Rest架构中。JSON序列化方式可以使用的第三方jar有很多,比如最常用的,也是SpringBoot中自带的JSON序列化方式:Jackson,以及Alibaba的用起来很方便的Fastjson,以及Android中常用的Gson。下面是三种工具的使用方式。
感觉Jackson用起来不是很方便,使用Jackson需要创建一些前置对象,下面是他最简单的序列化反序列化方式:
Fastjson是开发中公司用的较多的JSON框架,用起来比较方便,而且速度也很快,下面是他的示例代码:
Gson是Google的一款JSON序列化框架,使用起来也是比较方便的,笔者是很久之前还在学习Android的时候接触的,算是接触的最早的JSON框架,但是对其使用并不是很了解:
Protocal Buffer是Google提供的一种数据序列化协议,是一种轻便高效的结构化数据存储格式,适合作为数据存储或者RPC数据交换格式。可用于通讯协议、数据存储等领域的语言无关、平台无关、可扩展的序列化结构数据格式。
实现一个Protocol Buffer较为复杂,这里使用百度提供的工具包 jprotobuf
:
代码演示:
针对字节数据进行了压缩,所以生成的数据较小,所以传输效率较高
针对数据进行了缓存
Hessian序列化的方式同样是跨语言的,是一种二进制的序列化方式。值得一提的是,Hessian序列化的速度很快,但是序列化的结果所占的字节数却很大。