序列化协议对比(Java / JSON / ProtoBuf / Hessian)
做分布式系统,序列化是绕不过去的坎。你的对象怎么变成字节流?字节流怎么变回对象?这就是序列化要解决的问题。
我见过太多团队在这上面踩坑:用 Java 序列化做微服务通信,结果带宽跑满、CPU 飙升;或者用了 JSON 做高性能场景,结果 GC 频繁。
今天我们就来把常见的序列化方案讲清楚,帮你在不同场景下做出正确的选择。
一、序列化基础概念
1.1 什么是序列化
序列化就是对象到字节序列的转换:
1.2 序列化的应用场景
1.3 衡量指标
二、Java 原生序列化
2.1 使用方式
2.2 优点
- JDK 内置,不需要引入依赖
- 实现简单
- 支持复杂对象图
- 支持对象循环引用
2.3 ❌ 缺点:性能差
Java 序列化有严重的性能问题:
对比测试:
2.4 ❌ 安全问题
Java 序列化有反序列化漏洞:
Spring、Kryo 都受到过反序列化漏洞影响。
生产环境中,禁止直接反序列化不可信来源的数据。如果必须,要有白名单校验机制。
三、JSON 序列化
3.1 Jackson 使用
3.2 FastJSON 使用
3.3 优点
- 可读性强:JSON 文本人类可以直接阅读和调试
- 跨语言:所有语言都支持 JSON
- 格式简单:易于理解和维护
3.4 缺点
四、Protocol Buffers
4.1 proto 文件定义
4.2 生成 Java 代码
生成后的代码:
4.3 使用示例
4.4 优点
4.5 ❌ 缺点
- 需要定义
.proto文件 - 需要编译,修改协议要重新生成
- 学习曲线
五、Hessian
5.1 Hessian 的特点
Hessian 是一种动态的二进制序列化协议,不需要预定义 schema:
5.2 Spring 的集成
5.3 优点
- 动态序列化,不需要预定义
- 跨语言(Java、C++、Python、.NET、PHP...)
- 序列化后体积小
- 在 Java 生态中广泛使用
5.4 缺点
- 不如 ProtoBuf 快
- 类型信息不够丰富
- 存在反序列化漏洞
六、Kryo
6.1 使用示例
6.2 注册类 ID
6.3 Kryo 序列化池
频繁创建 Kryo 实例有开销,可以使用对象池:
七、性能对比
7.1 综合对比表
7.2 选型决策
八、生产避坑
8.1 ❌ 错误示范:使用 Java 序列化做微服务通信
正确做法:用 JSON 或 ProtoBuf:
8.2 ❌ 错误示范:没有处理序列化版本变化
正确做法:显式声明 serialVersionUID,并在类结构变化时更新:
8.3 ❌ 错误示范:序列化敏感数据未加密
正确做法:对敏感数据加密或使用 TLS:
九、面试追问链
第一层:基础概念
面试官问:"什么是序列化?为什么需要序列化?"
序列化是将对象转换为字节流的过程,用于网络传输、缓存存储等。反序列化是反向过程。不同系统/语言之间通信需要序列化来编码和解码数据。
第二层:常见方案
面试官问:"你知道哪些序列化方案?"
Java Serializable(慢、重、不安全)、JSON(可读、跨语言、慢)、ProtoBuf(快、小、跨语言、需要 proto 文件)、Hessian(动态、跨语言、较快)、Kryo(Java 最快、不跨语言)。
第三层:选型决策
面试官追问:"微服务之间通信用什么序列化方案?"
如果是 HTTP JSON,通用性好;如果追求性能,用 ProtoBuf 或 Kryo。还要考虑团队能力、是否需要跨语言等因素。
第四层:安全考虑
面试官追问:"Java 序列化有什么安全问题?"
Java 反序列化漏洞,攻击者可以构造恶意序列化数据来执行任意代码。生产中不要直接反序列化不可信数据,或者使用黑名单/白名单机制。
【学习小结】
- Java 序列化:慢、大、不安全,尽量不用
- JSON:可读、跨语言、适中性能
- ProtoBuf:快、小、跨语言、需要预定义
- Hessian:动态序列化、跨语言
- Kryo:Java 最快、不跨语言
- 选型看场景:HTTP API 用 JSON,内部通信用 ProtoBuf/Kryo