什么时候需要序列化?
当你程序里的对象要存储到硬盘或者通过网络传输的时候,你的对象就需要序列化成二进制字节数组。那么,序列化对我们的程序到底有多大影响,如何判断一个序列化框架的好坏?我们一般从如下几个方面来评定一个序列化框架的优劣。
1、序列化反序列化的速度->直接影响了程序的性能。
2、序列化后字节流的大小->可能会占据你更多的带宽,特别是外网带宽很贵。
3、是否跨平台跨语言->影响了你程序的拓展性。
接下来介绍一下我常用的三种序列化方式。
一、Jdk序列化
Jdk序列化是最先接触的序列化方式,一个对象需要序列化,需要实现Serializable接口,并改写serialVersionUID字段值。
它会将类的信息和状态信息一起序列化到一个二进制数组里,保存到磁盘或者通过网络传输,当我们从磁盘或者网络收到这个二进制数组时,就可以通过这个数据进行反序列化来还原我们程序中的对象,但是这个序列化方式有如下缺点,一般不建议使用:
1、序列化反序列化的性能较长,会导致程序性能变慢。
2、序列化产生的码流较大,会占用更多的磁盘和带宽。
3、只能在Java里使用,不能跨语言使用。
二、Json序列化
在Json序列化之前,我们还用过xml的方式来保存数据,json相比xml,精简了不少,从xml的标签对改为了json了字段名,也不用进行繁重的dom解析,现在的xml我们常见的是一些配置文件采用了这个格式。
Json序列化是目前我工作中用到最主要的序列化方式,不管是Http的调用,还是缓存数据的序列化,90%以上都是用这个,有一批优秀的Json序列化框架,如FastJson、Jackson等。
三、ProtoBuf序列化
ProtoBuf序列化是公认的最好的序列化框架之一。具有极佳的序列化反序列化速度和极小的码流,非常适合追求极致性能的应用程序。
1、这么优秀的原因:
把数据变小一点,对于一条数据,json的表示方法:
{ "age": 30, "name": "zhangsan", "height": 175.33, "weight": 140 }
protobuf省去了很多中间冗余的{}"":,等,同时传输的过程中省略了null值
采用tag技术,替代json的key/value,使用tag的话,一般只占用1个字节,而json的key一个字符就占1个字节
在传输的过程中,会对整数进行压缩,例如一个long类型的1,会压缩成byte类型的1,这些是在内部操作的,对开发而言,是透明的
protobuf是采用tag/leg/value的方式来保存数据的,读到某个字段(tag)后,直接获取长度leg,解析出来就是所需要的值,而json需要解析字符串才可以办到。
2、如何使用:
引入依赖:
<dependency>
<groupId>com.google.protobuf</groupId>
<artifactId>protobuf-java</artifactId>
<version>3.5.1</version>
<scope>compile</scope>
</dependency>
编写proto文件
syntax = "proto3";
option java_package = "chen.huai.jie.sdn.message.proto";
message StoreContent {
string topic =1;
string key =2;
bytes message=3;
}
导入protoc.exe可执行文件
利用命令来生成proto对应的java文件
protoc --java_out=..\java --proto_path=. *.proto
最终生了我们java里需要用到的文件,每次改动proto文件后都需要重新生成。
接下来我们就可以在代码里利用proto快乐的玩耍了。
关于protobuf的性能,可以参考我另一篇博客,里面有对json和protobuf的序列化性能对比
总结:
不是说没有其他的序列化方式,只是我对这三种用的最多,其他的用过了我也会在这里继续补充。极致性能体验推荐使用protobuf,真的不错。