JJava 知识库
JAVA INTERVIEW

高频面试题

Java基础进阶约 3 分钟

微服务之间传对象、Redis 存对象、Kafka 发消息时,你们怎么选择序列化方式?踩过什么坑?

参考回答约 3 分钟 · 口语表达
先说结论

这个问题我会先说项目结论:序列化是把对象转换为可传输或保存的数据格式,反序列化执行逆过程。业务系统通常根据可读性、体积、性能、跨语言和兼容性选择协议,不应默认使用 JDK 原生序列化。 JDK 序列化依赖 Serializable,serialVersionUID 用于版本校验,transient 字段默认不参与序列化。

01

我会先交代项目背景和选型结论。比较 JDK、JSON 和二进制序列化,并分析兼容性、安全性与选型原则。序列化是把对象转换为可传输或保存的数据格式,反序列化执行逆过程。业务系统通常根据可读性、体积、性能、跨语言和兼容性选择协议,不应默认使用 JDK 原生序列化。 JDK 序列化依赖 Serializable,serialVersionUID 用于版本校验,transient 字段默认不参与序列化。它与 Java 类型绑定较深,且历史上存在危险的反序列化调用链。

02

具体落地时,我会沿着实际调用链来讲。沿着「遍历对象图 → 确定字段与类型标识 → 编码为字节 → 存储或跨网络传输 → 按兼容规则重建对象」观察输入、状态与输出,这些阶段都可以从日志、指标或源码里验证。 遍历对象图 序列化器从根对象遍历引用关系,循环引用、共享引用和懒加载代理都会影响结果与大小。 确定字段与类型标识 协议需要决定字段编号、类型信息、空值和默认值;使用字段名更直观但体积通常更大。 java.io.ObjectInputFilter:原生反序列化类与尺寸过滤。 com.google.protobuf.UnknownFieldSet:Protobuf 未知字段兼容保留。

03

参数和容量不能靠默认值,我会结合业务量来定。准备旧版、新版和含未知字段三组消息,执行双向兼容测试;同时生成超深对象图和超大数组验证过滤器在分配前拒绝。

04

效果要用数据证明,线上问题也要能闭环。固定输入和基线 先在没有故障注入的环境执行上述配置,固定数据规模、并发度、运行时版本和预热时间。以「报文 P99 大小」为主基线,记录值应满足「小于 Broker/网关上限 50%」;同时保存 报文大小分布、序列化与反序列化耗时,使后续变化能够回到同一时间轴比较。 订单事件把 Java 类名和完整对象直接写入消息。服务重构包名后,历史消息无法反序列化,回放链路中断。改用稳定事件 Schema、字段编号与兼容性检查,并把领域对象和传输 DTO 分离后,生产者与消费者才能独立演进。 反序列化不可信类型导致代码执行风险:报文大小分布:拒绝 Java 原生序列化外部输入。

05

最后我会主动说明这个方案不适合什么场景。方案:可读性:跨语言:体积与速度:演进方式:常见场景。 JDK 原生:低:差:体积较大:依赖 Java 类结构:受控的短期内部数据,通常不推荐做公共协议。 JSON:高:好:体积较大、解析成本中等:依靠字段约定:HTTP API、配置、调试友好链路。 Protobuf:低:好:紧凑且高效:schema + 字段编号:RPC、消息、跨语言高吞吐链路。