什么是序列化?
把数据或者对象信息转换成可以持久化或者在进行传输的数据格式的一个过程。序列化的码流太大的话会影响网络传输的性能。
序列化的使用场景包括
1你要把数据进行持久化,无论你是持久化到磁盘和数据库,都要把数据进行序列化。
2 在网络间以字节流的形式进行传输,需要把数据进行序列化
3 让数据在进程间进行传递
java序列化:
java为序列化提供了两个接口Serializable 和 Externalizable两个接口,但是Externalizable是继承自Serializable接口,Externalizable接口需要在实现该接口的类中提供一个public的无参构造器,并重写writeExternal()和readExternal()两个方法。
transient关键字:
transient关键字修饰的字段,在对象进行序列化的时候,该字段不会进行序列化
此外被static修饰的字段,无论是否被transient修饰,该字段都不会被序列化
拓展:被static修饰的字段不属于某个对象,而是有多个对象共享的,被static修饰的成员变量属于类(多个对象访问或修改statix修饰的成员变量时,一旦其中的一个对象对static成员变量进行了修改,其他的对象的static成员变量值也会变化,即多个对象共享一个static的成员变量)
序列化版本号serialVersionUID:
这个属性是为了控制对象中字段的增减是否兼容的问题。例如添加了一个字段,只要保持序列化版本serialVersionUID 不变,就能正常反序列化。如果修改了serialVersionUID就会出现serialVersionUID不一致的错误
每一个保存在磁盘的序列化对象都会有一个唯一的序列化编号。如果序列化编号已经存在就直接输出序列编号,如果不存在就直接输出序列化的对象
例如:
Person p1 = new Person();
Person p2 = new Person();
p1.setName("张三");
p2..setName("李四");
//p1和p2会产生两个不同的编号
延伸:
项目中详见的序列化框架就是java的序列化、json、xml。其他还常用的序列化框架有hessian,protobuf和Kryo
jdk的缺点:
1 序列化的码流大,占用存储空间大,网络传输占用带宽高,性能低
2 无法跨语音,在jdk序列化操作时是使用了java语言内的私有协议,在对其他语言进行反序列化的时候有严重阻碍
hessian:
Hessian是一款支持多种语言进行序列化操作的框架技术,同时在进行序列化之后产生的码流也较小,处理数据的性能方面远超于java内置的jdk序列化方式。在SerializerFactory里面有getSerializer和getDefaultSerializer的函数,专门用于提取这些序列化和反序列化的工具类,这样可以避免在使用该工具类的时候又要重新实例化,这些工具类都会被存储到不同的ConcurrentHashMap里面去。对于hessian3.0时候的Serializer/Derializer实现功能没有考虑到对于异常信息进行序列化处理,因此如果遇到相应问题的朋友可以考虑将hessian的版本提升到3.1.5以上。
Kryo:
Kryo是一种非常成熟的序列化实现,已经在Twitter、Groupon、 Yahoo以及多个著名开源项目(如Hive、Storm)中广泛的使用,它的性能在各个方面都比hessian2要优秀些,因此dubbo后期也开始渐渐引入了使用Kryo进行序列化的方式。Kryo不支持没有无参构造函数的对象进行反序列化,因此如果某个对象希望使用Kryo来进行序列化操作的话,需要有相应的无参构造函数才可以。
protobuf:
google protobuf是一个灵活的、高效的用于序列化数据的协议。相比较XML和JSON格式,protobuf更小、更快、更便捷。google protobuf是跨语言的,并且自带了一个编译器(protoc),只需要用它进行编译,可以编译成Java、python、C++、C#、Go等代码,然后就可以直接使用,不需要再写其他代码,自带有解析的代码。
protobuf相对于kryo来说具有更加高效的性能和灵活性,能够在实际使用中,当对象序列化之后新增了字段,在反序列化出来的时候依旧可以正常使用。(这一点kryo无法支持)
protostuff:
protostuff 是基于protobuf 实现序列化方法,它相较于protobuf 的优点是,在几乎没有损耗protobuf的性能的情况下不用写.proto后缀文件来实现序列化