serialVersionUID的使用及历史serialVersionUID兼容问题

209 阅读1分钟

问题现象

发布需求代码,一天后发现redis内存激增告警,回滚代码后,问题仍然没有解决。

问题分析处理过程

1.导出reidsKey,分析增长数据

发现是以 session_key_*** 开头的 key 激增,分析应该是网关,且激增时间开始节点,是网关需求发版时间

2.监控线上日志

发现有频繁反序列化异常

image.png

3.查看类源代码及git修改记录

发现反序列化异常的类的父类 实现了 【java.io.Serializable】,但该类没有定义 serialVersionUID

4.查看反序列化生成对象

了解 session 对象是存redis,然后反序列化构造,生成新session后,因为代码逻辑原因,并没有替换新session,一直使用老session,所以导致错误数据用户一直反复登录。

5.结论

1.如果没有自定义 serialVersionUID, JDK会根据类属性类型,生成 serialVersionUID,当类属性有更改,serialVersionUID将会重新生成。

问题解决方案

1.方案1

自定义serialVersionUID,且serialVersionUID定义为 stream 流中的 serialVersionUID,但代码回滚后又生成多种serialVersionUID的数据,无法完全覆盖历史数据,只能兼容部分报错数据。

2.方案2

删除所有redis数据,用户没有seesion,全都重新登录替换。缺点:影响用户使用,体验

3.方案3(采用)

重写ObjectInputstream,读取stream中的serialVersionUID 和 local Class 的 serialVersionUID 做对比,如果不同,强制将 local Class 的serialVersionUID写入stream,保证serialVersionUID一致,数据反序列化兼容

ByteArrayInputStream byteStream = new ByteArrayInputStream(bytes);
/**
 * 原代码:
 * ObjectInputStream objectInputStream = new ObjectInputStream(byteStream); 
 */
ObjectInputStream objectInputStream = new CompatibleInputStream(byteStream); 
AccountInfo result = objectInputStream.readObject();

参考文档:
code84.com/876671.html blog.csdn.net/swjtu_yhz/a…