修改cdfs.events.C类部署后出现java.io.InvalidClassException序列化兼容错误
问题根因
- Java序列化规则中,只要父类实现了
Serializable接口,所有派生子类默认都具备序列化能力,无需显式声明实现接口。你的B、C类因为继承了可序列化的A类,天然支持序列化。 - 未显式声明
serialVersionUID的可序列化类,JVM会在运行时根据类的字段、方法、结构等特征动态计算生成唯一值,你修改C类为为空类后,类结构变化导致JVM新计算的serialVersionUID和旧版本生成的不一致,反序列化时就会抛出兼容性异常。异常中出现的版本号是JVM为C类单独计算的动态版本号,和父类A显式声明的serialVersionUID无关,只有当类自己没有声明serialVersionUID时才会触发JVM动态计算逻辑。 - 你认为未触发序列化操作是因为忽略了容器/中间件的隐式序列化逻辑:Tomcat默认开启会话持久化功能,正常关闭服务时会把Session中存储的所有对象序列化到磁盘的
SESSION.ser文件,服务重启时会自动读取该文件反序列化恢复会话数据,这个过程是无业务侵入的,极易被忽略。之前修改同类逻辑未触发异常,大概率是此前重启为强制杀进程,没有走Tomcat正常关闭的会话持久化流程,没有遗留的序列化文件需要反序列化。
排查步骤
- 检查Tomcat配置:查看全局
conf/context.xml或应用内META-INF/context.xml文件,确认是否配置了持久化会话管理器,默认配置下Tomcat会将会话序列化到work/Catalina/[域名]/[应用名]/目录下。 - 排查应用依赖的中间件:确认是否使用了Guava Cache、Caffeine、Ehcache等支持磁盘持久化的本地缓存组件,或是其他会将对象落地存储的框架,这些组件也可能无感知触发序列化操作。
- 查找遗留序列化文件:进入Tomcat对应应用的work目录,搜索后缀为
.ser的文件,确认是否存在旧版本C类序列化后的遗留文件。
解决方法
紧急修复方案
停止Tomcat服务,删除对应应用work目录下的所有.ser序列化文件(通常为SESSION.ser),再重启服务即可,删除旧序列化数据后不会再触发旧类的反序列化逻辑。
永久修复方案
- 所有继承自A的派生类(B、C等)统一显式声明
serialVersionUID,类结构兼容迭代时不修改该值即可避免JVM动态生成的版本号冲突问题,示例代码:
// 版本号可自定义,也可直接复用A类定义的serialVersionUID值 private static final long serialVersionUID = 1L;
- 若不需要会话持久化能力,在Tomcat的
context.xml中添加配置<Manager pathname="" />即可关闭会话持久化功能,从根源避免容器隐式触发序列化操作。 - 清理不必要的缓存持久化配置,关闭所有业务无感知的对象磁盘落地逻辑。
内容的提问来源于stack exchange,提问作者Sijo Kurien
相关产品推荐
相关产品推荐

