记一次Serializable序列化和反序列化导致的线上报错

个人博客地址:https://blog.flycat.tech/archives/serializable-serialization-deserialization-online-error

背景

某个需求上线后告警群里面收到了报错的消息,报错摘要如下:

Cannot deserialize; nested exception is org.springframework.core.serializer.support.SerializationFailedException: Failed to deserialize payload. Is the byte array a result of corresponding serialization for DefaultDeserializer?; nested exception is java.io.InvalidClassException: com.i61.draw.common.model.CommonTeacherInfo; local class incompatible: stream classdesc serialVersionUID = -5929137330017767311, local class serialVersionUID = -2020770249958646674 org.springframework.data.redis.serializer.SerializationException: Cannot deserialize; nested exception is org.springframework.core.serializer.support.SerializationFailedException: Failed to deserialize payload. Is the byte array a result of corresponding serialization for DefaultDeserializer?; nested exception is java.io.InvalidClassException: com.xxx.xxx.common.model.CommonXxxxxxInfo; local class incompatible: stream classdesc serialVersionUID = -5929137330017767311, local class serialVersionUID = -2020770249958646674

排查

通过报错的栈信息,定位到问题代码第66行,可以看到是调getTeacherInfoList这个方法时,读取缓存反序列化失败了。

源码图片1

源码图片2

将报错信息复制到GPT,GPT的回答如下:


这个错误表明在反序列化过程中发生了问题,具体原因是由于 CommonXxxxxxInfo类的版本不一致导致的。在Java中,当一个类被序列化时,会生成一个包含版本信息的serialVersionUID。如果在反序列化时,类的版本信息不匹配,就会抛出 InvalidClassException

在你的具体情况中,错误信息中提到了两个不同的serialVersionUID值:

  • stream classdesc serialVersionUID = -5929137330017767311
  • local class serialVersionUID = -2020770249958646674

这表示你的代码中的 CommonXxxxxxInfo类在两个地方的版本不一致。可能的原因和解决方法包括:

  1. 类的版本变更: 可能是 CommonXxxxxxInfo类在序列化和反序列化之间发生了更改,可能是添加、删除或修改了字段。确保在序列化和反序列化的代码之间,CommonXxxxxxInfo类的版本是一致的。

  2. 显式指定serialVersionUID: 你可以在 CommonXxxxxxInfo类中显式指定serialVersionUID,以确保它在类发生变更时仍然保持一致。你可以在类中添加如下代码:

    javaCopy code

    private static final long serialVersionUID = -5929137330017767311L; // 使用实际的值替换

    在类发生变更时,手动更新这个值。

  3. 检查依赖版本: 如果 CommonXxxxxxInfo类是从外部库引入的,确保你的应用程序和库中使用的类版本一致。可能你的应用程序使用了一个不同版本的 CommonXxxxxxInfo类。

通过解决这些问题,你应该能够解决反序列化问题。在做任何更改之前,请确保备份你的代码以防意外。


其中有提到,由于没有指定serialVersionUID,当添加、删除或修改了字段,其默认的serialVersionUID会变更,查看CommonXxxxxxInfo类的git提交记录,果然添加了字段。

CleanShot 2024-03-05 at 00.32.39.png

解决

  1. 手动生成serialVersionUID值

总结

以前看到说继承了Serializable最好指定serialVersionUID,但在实际使用中,发现似乎不指定也没有问题,所以即使继承了这个接口也很少会再手动指定UID,所以以后遇到需要序列化(尤其是使用jdk序列化器)的地方,都应该:

  1. 需要序列化的地方(尤其是使用jdk序列化起)都要继承Serializable接口
  2. 手动生成serialVersionUID值
  3. 如果没有指定UID,当类结构发生变化(增减改字段)时,默认的UID会变化,导致序列化/反序列化失败

小提示:生成serialVersionUID值时可以使用IDEA插件GenerateSerialVersionUID

  • 23
    点赞
  • 29
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值