为什么需要序列化和反序列化
- 存储对象/持久化:序列化可以将内存中的对象状态转换为字节流,然后保存到硬盘上,这样即使程序关闭,下次也可以从磁盘上恢复这个对象的状态。或者将对象序列化后存储在数据库、文件或其他持久存储介质中,便于以后检索或恢复。
- 网络通信/RPC(远程过程调用):在网络传输中,发送方需要将内存中的对象转换成字节流形式通过网络发送给接收方。接收方收到这些字节流后再将其还原成对象,这一过程就需要用到序列化和反序列化。在分布式系统中,客户端和服务端之间的交互通常依赖于序列化技术来传递请求和响应。
当前Java有哪些序列化和反序列化方法
Java自带的方法
Java.io.ObjectOutputStream 和 Java.io.ObjectInputStream
序列化:使用ObjectOutputStream类将对象写入到输出流中。
反序列化:使用ObjectInputStream类从输入流中读取对象。
处理成XML
JAXB(Java Architecture for XML Binding)
适用于将Java对象映射到XML文档中。
使用javax.xml.bind.Marshaller进行序列化,使用Unmarshaller进行反序列化。
处理成JSON
通过GSON,FASTJSON,Jackson等序列化和反序列化JSON数据
Protobuf
Google的Protocol Buffers一种高效的序列化协议,通常用于网络通信。需要先定义.proto文件来描述消息结构,然后通过工具生成Java类。使用生成的类的writeTo方法序列化,使用parseFrom方法反序列化。优势是能够跨语言,会对序列化文件进行压缩,压缩效果不错,性能也可以接受。不过最大的优点还是跨语言。只需要双方都适用proto即可。比如Java通过protobuf序列化后存入数据库或文件系统,Golang去数据库或文件系统直接读取。或者是直接RPC,HTTP网络通信时使用。
Kryo
Kryo 是一个 Java 序列化库,它提供了非常高效的对象到字节序列的转换功能。Kryo 被设计用于性能敏感的应用程序,比如大规模数据处理、实时计算框架(例如 Apache Storm 和 Apache Spark)以及高性能网络服务。相比于 Java 内置的序列化机制,Kryo 提供了更好的性能和灵活性。
Protobuf和Kryo对比
Kryo | Protocol Buffers (protobuf) | |
---|---|---|
性能 | 高效,通常比Java默认序列化快得多 | 高效,特别是对于大量数据传输 |
数据格式 | 二进制格式 | 二进制格式 |
灵活性 | 动态序列化,无需预先定义消息结构 | 静态序列化,需要预先定义.proto文件 |
语言支持 | 主要针对Java | 多语言支持,包括Java、C++、Python等 |
易用性 | 直接序列化任何实现了Serializable的Java对象 | 需要定义.proto文件来描述消息结构 |
可扩展性 | 可以注册自定义的序列化器 | 可以定义复杂的消息结构,包括嵌套消息 |
兼容性 | 类结构改变可能导致兼容性问题 | 具有良好的向后兼容性,可通过字段标记处理 |
安全性 | 较低,可以序列化任何Java对象 | 较高,需要定义.proto文件 |
数据大小 | 生成的数据通常较小 | 数据紧凑,比XML等文本格式小得多 |
序列化速度 | 快速 | 快速 |
反序列化速度 | 快速 | 快速 |
学习曲线 | 适中,需要理解Kryo的基本用法 | 较高,需要理解.proto文件的语法及编译过程 |
工具支持 | 较少,但有基本的命令行工具 | 丰富的工具支持,包括编译器和IDE插件 |
总结
当场景是跨语言时,优先使用Protobuf。
当场景对性能要求很高时或者说性能敏感时,使用Kryo。