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


    背景

    去年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」,有惊喜哦!

  • 相关阅读:
    用java在mysql中随机插入9000 000条数据
    java连接mysql的一个小例子
    JDK环境变量配置
    JVM工作原理
    线程和进程的区别
    java实现链表
    内连接、外连接、左连接、右连接
    udp协议
    要看的东西
    eclipse快捷键
  • 原文地址:https://www.cnblogs.com/haha12/p/12605751.html
Copyright © 2020-2023  润新知