【超详细讲解】什么是序列化和反序列化?
目录
一、什么是序列化(Serialization)?
举个直观的例子
二、什么是反序列化(Deserialization)?
三、为什么需要序列化?
四、常见的序列化格式对比
五、序列化底层是怎么做的?
序列化过程:
反序列化过程:
六、序列化/反序列化常见坑
七、实际工程中应该怎么做?
八、总结
在实际项目开发中,“序列化(Serialization)”和“反序列化(Deserialization)”几乎无处不在。
但很多刚入门的同学,对它们的理解还停留在“转成字符串、传来传去”这么简单的层面。
其实,序列化的作用、原理、选择不同序列化协议的考量、安全风险、性能优化,每一个点都值得深入探讨!
一、什么是序列化(Serialization)?
序列化是将对象的状态转换为可存储或可传输格式的过程。
对象在内存中一般以特定的数据结构(指针、引用、哈希表、链表等)存在,直接传输内存数据是不可靠的(不同机器架构不同、数据对齐不同、指针无意义等问题)。
所以我们需要将对象转换成连续的字节流(或标准格式的文本),使得:
-
可以写入磁盘文件
-
可以通过网络发送到远端
-
可以被其他进程或设备正确解析
简单来说,序列化是让数据“离开内存,去旅行”的必备装备。
举个直观的例子
C++中的一个对象:
struct User {std::string name;int age;
};
User u{"Alice", 24};
序列化后,可能得到这样一段JSON字符串:
{"name": "Alice", "age": 24}
或者变成一段二进制流,比如:
[0x05][Alice][0x18]
二、什么是反序列化(Deserialization)?
反序列化就是序列化的逆过程。
把收到的字节流或文本格式数据,还原成内存中的对象或数据结构,供程序继续操作。
比如:
-
从磁盘读取一段JSON数据
-
解析网络收到的一段Protobuf消息
-
把Redis里缓存的对象取出来恢复成原始对象
这些都是反序列化的应用。
三、为什么需要序列化?
我们来列一下常见场景:
应用场景 | 为什么需要序列化 |
---|---|
网络通信 | TCP/UDP传输的数据必须是字节流,无法直接传对象 |
本地持久化 | 把程序状态保存到磁盘,下次能恢复 |
跨平台数据交换 | 不同系统、不同语言之间必须用标准格式 |
缓存系统 | Redis、Memcached存的是序列化后的对象 |
消息队列 | Kafka、RabbitMQ里的消息通常也是经过序列化的 |
RPC调用 | gRPC、Thrift调用远端服务需要将请求和响应序列化 |
没有序列化,现代分布式系统、微服务体系几乎无法正常运作!
四、常见的序列化格式对比
不同场景适合不同的序列化格式,常见的几种包括:
格式 | 优点 | 缺点 | 典型应用 |
---|---|---|---|
JSON | 人类可读、跨平台、广泛支持 | 体积大、解析慢 | 前后端接口、配置文件 |
XML | 结构复杂、可扩展性好 | 体积更大、解析更慢 | SOAP服务、老系统 |
Protobuf | 体积小、速度快、强类型定义 | 不易读、需要提前定义proto文件 | gRPC、分布式系统内部通信 |
MessagePack | 比JSON小、解析快 | 不如Protobuf精简 | 移动端、缓存系统 |
FlatBuffers | 零拷贝、超高速访问 | 使用复杂、生成文件较大 | 游戏开发、大量实时数据场景 |
Avro | 支持Schema进化(动态变化) | 较重 | 大数据(Hadoop生态) |
▶ 简单总结:
-
传给人看的用 JSON
-
高性能通信用 Protobuf
-
体积敏感场景用 MessagePack/FlatBuffers
-
大数据流用 Avro
五、序列化底层是怎么做的?
不同协议实现不一样,但总体过程类似:
序列化过程:
-
遍历对象的各个成员
-
把成员名和值按照某种规则编码
-
将编码结果组织成二进制流或文本格式
反序列化过程:
-
按照协议解析字节流或文本
-
提取字段信息
-
重新创建对象并赋值
比如 Protobuf 就是通过 proto 文件定义消息结构,在序列化时将字段编号、数据值压缩成紧凑的二进制格式。
六、序列化/反序列化常见坑
-
版本兼容问题
-
加字段、删字段时,旧版本客户端可能崩溃!
-
解决方案:设计支持“向前兼容”和“向后兼容”的协议(比如 Protobuf 就支持)
-
-
性能瓶颈
-
大对象频繁序列化/反序列化,CPU和内存开销大
-
解决方案:缓存序列化结果、优化协议选择
-
-
安全风险
-
反序列化时如果处理不当,可能被黑客注入恶意数据(反序列化漏洞)
-
解决方案:只信任可信源数据、限制反序列化对象类型
-
-
浮点数精度问题
-
JSON等文本协议保存浮点数时可能丢失精度
-
-
指针、引用、共享对象问题
-
C++等语言中的裸指针、智能指针需要特别小心处理
-
七、实际工程中应该怎么做?
▶ 选好序列化协议
-
轻量级API通信选JSON
-
高性能微服务内部通信选Protobuf
-
超高频、大量小数据可以考虑FlatBuffers
▶ 优化性能
-
尽量复用对象
-
预先分配好内存
-
批量处理而不是逐条处理
▶ 注意安全问题
-
不要反序列化不可信来源的数据
-
限制反序列化类的白名单
-
检查数据大小、结构合理性
八、总结
序列化和反序列化是现代系统数据流动的桥梁。
-
序列化让数据可以跨内存、跨进程、跨机器传递;
-
反序列化让数据回到可以操作的对象状态;
-
正确、合理、安全地使用它们,是开发可靠系统的基础技能。