一次线上升级大规模报错后,我又重新学习了序列化!

背景

去年9月份时候fastjson出现过一个漏洞,需要升级到1.2.60,旧版本是1.2.12,测试环境验证完毕后上线,上线几分钟瞬间几百封报错邮件,当时瞬间心里特紧张,但是表面上得装着没事,咱能搞定,哈哈,还好迅速定位并解决了问题。

系统流程

出问题模块流程比较简单,需要查询一些数据,先从Redis查询,没有再查询数据库并把结果放到Redis中缓存。

问题排查

报错异常信息如下:

java.io.InvalidClassException: com.alibaba.fastjson.JSONObject; local class incompatible: stream classdesc serialVersionUID = -7894253080042154647, local class serialVersionUID = 1

看到报错可能你已经明白了,反序列化时候版本不一致导致的问题,那么问题是如何产生的呢?

Fastjson1.2.60源码的JSONObject类里有下面一行代码:

 private static final long         serialVersionUID         = 1L;

而1.2.12版本源码的JSONObject类里没有定义serialVersionUID。

Java的序列化机制是通过判断类的serialVersionUID来验证版本一致性的,在进行反序列化时,JVM会把传来的字节流中的serialVersionUID与本地相应实体类的serialVersionUID进行比较,如果相同就认为是一致的,可以进行反序列化,否则就会出现序列化版本不一致的异常

当实现java.io.Serializable接口的类没有显式地定义一个serialVersionUID变量时候,Java序列化机制会根据编译的Class自动生成一个serialVersionUID作序列化版本比较用,这种情况下,如果Class文件(类名,方法明等)没有发生变化(增加空格,换行,增加注释等等),就算再编译多次,serialVersionUID也不会变化的。

问题原因找到了,系统返回实体里存放了JSONObject的对象,系统上线后用户访问时候如果缓存有数据,就会出现反序列化版本不一致的情况,导致出现异常。

解决方案

先说下我的方案,使用新版本的jar包,把设置缓存代码里key的前缀修改下,这样就不会使用旧的缓存进行反序列化,问题解决。

例如:

//原始代码
 @CacheEvict(value="RedisCache11",key="'user:test:'+#obj.id",beforeInvocation=true)
 //修改后代码
 @CacheEvict(value="RedisCache11",key="'user:test2020:'+#obj.id",beforeInvocation=true)

以上是我的一种的解决方案,如果你有其他的方案,欢迎留言沟通哦!

推荐阅读

1.记一次线上Mysql慢查询排查经历!
2.彻底理解cookie、session、token
3.阿里面试官:分别说说微信和淘宝扫码登录背后的实现原理?
4.一分钟带你了解下MyBatis的动态SQL!
5.原创 | 我是如何解决POI解析Excel出现的OOM问题的?


如果觉得文章不错,希望可以随手转发或者”在看“哦,非常感谢哈!

关注下方公众号后回复「1024」,有惊喜哦!

posted @ 2020-03-31 15:55  Java碎碎念  阅读(553)  评论(0编辑  收藏  举报