JDK 序列化问题排查

Sherwin.Wei Lv7

JDK 序列化问题排查

提供一个线上 JDK 序列化问题排查案例,虽然比较基础,但在我任职的公司中出现过两次,而且是 5 年及以上工作经验的同事写的 bug。供大家参考

新加了个字段,然后发版,上线就发现了报错。

企业微信截图_b2889ba7-376e-48e4-b5f2-dc97be3f85db.png

就加了一个字段,怎么就序列化出错了呢?

复现错误

简单定义一个 Yes 类,可以看到就三个字段。

企业微信截图_2fa10424-f352-4221-9356-18719f003c32.png

简单 new 了一个对象,直接塞入到 redis 中。

企业微信截图_408cf1f8-2fa4-4adf-97c0-16f974b6992c.png

可以看到 value 看起来是乱码,这里用的是 JDK 序列化

企业微信截图_2b57e31d-a4b7-44aa-89be-6aa7fa53b406.png

现在我们在 Yes 类加个 hobby 这个字段,然后再从 redis 里面获取之前存入的值然后打印.

企业微信截图_d1b2d73a-ce57-40b6-a147-1419beff8f42.png

看看,是不是报错了,无法反序列化,bug 复现了?

企业微信截图_ed847751-7266-4b86-b9a4-31da7c84089d.png

我们再详细看下报错信息,里面有一行字,这就是抛错的具体原因,流里面 serialVersionUID 和本地的 serialVersionUID 不一样的

企业微信截图_012d538f-b037-4f58-9cfd-dc288b1b8140.png

为什么会这样?

因为用的是 JDK 序列化,虽然 class 实现了 Serializable 接口但没显示定义 serialVersionUID ,这样一来序列化时会根据当前类的信息计算得到一个 serialVersionUID 。

在序列化存入 redis 后,我又把代码里的 class 的结构变了,这时候再从 redis 获取之前的值反序列化,由于当前的 class 还是没有 serialVersionUID ,于是又会根据当前的类信息计算的 serialVersionUID ,而由于结构变了,类信息肯定变了,所以计算出来的 serialVersionUID 不一致。

因此序列化就失败。

这 serialVersionUID 就好比 class 的版本,版本变了序列化自然就失败了。

解决方式就是显示指定 serialVersionUID,这样就不需要动态计算了。

总结下:如果你了 JDK 序列化,一定记得要加 serialVersionUID ,不然就踩坑了。

还有,不是很推荐用 JDK 序列化,不管是性能还是存储都没有优势

至于具体选择哪种序列化合适,可以采用比如 Hessian、JSON、Protobuf 等。

以上的排查可以包装成你真正项目上的排查记录,还是很好套的。

扩展知识

Comments
On this page
JDK 序列化问题排查