`
chenzhou123520
  • 浏览: 4249762 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

由缓存导致的一个java序列化问题

阅读更多

背景描述:

项目是普通的java服务,以jar包的形式部署,前几天升级了一下服务,部署运行后跟踪日志发现时不时抛异常信息。

具体报错信息如下:

[2013-09-22 17:30:53,653] - [pool-3-thread-3] - ERROR - Caught IOException decoding 1061 bytes of data
java.io.InvalidClassException: com.chenzhou.test.model.VmCategoryMapper; local class incompatible: stream classdesc serialVersionUID = 1411005385568342784, local class serialVersionUID = -2356515191808014047

根据报错信息来看,是在反序列化VmCategoryMapper对象时发现serialVersionUID不一致,所以抛了IO异常。

 

我查看了一下VmCategoryMapper类的代码,具体如下(属性和方法就省略了):

package com.chenzhou.test.model;

import java.io.Serializable;
import java.util.List;


public class VmCategoryMapper implements Serializable {
	/**
	 * serialVersionUID:序列化ID.
	 */
	private static final long serialVersionUID = -2356515191808014047L;
	//省略了属性和方法
}

很纳闷的是,Eclipse给我自动生成的serialVersionUID就是-2356515191808014047,那异常信息声明中的反序列化得到的1411005385568342784是怎么得来的呢。

 

我通过SVN历史查看了一下VmCategoryMapper类的版本历史记录,发现历史版本中也没有使用过1411005385568342784作为serialVersionUID。

不过还是发现了一个线索,就是升级之前,VmCategoryMapper类我并没有显示地定义serialVersionUID,这次在优化代码的时候使用IDE自动生成了一个非默认的序列化ID。熟悉java序列化的人应该都了解,如果类实现了Serializable但是没有显式声明serialVersionUID,那么在程序编译时会自己生成这个版本序列化ID,所以我猜测1411005385568342784应该是我服务升级前默认生成的序列化ID。

 

但是问题依然存在,我升级后明明已经显示声明了serialVersionUID的值,为什么反序列化时会得到原来默认的值呢。我把线上的jar包中的VmCategoryMapper类的class文件进行了反编译,发现反编译出来的serialVersionUID是我代码中显示声明的值,也就是-2356515191808014047。说明jar包是正常的。

 

百思不得其解后,同事提醒我,什么时候会进行序列化和反序列化?

经他一提醒,我突然想到了对象在缓存中读取和更新时会进行序列化反序列化,很可能是缓存惹的祸,于是赶紧检查了一下缓存逻辑所在的DAO层的方法:

 

@ReadThroughSingleCache(namespace = CacheConst.VM_CATEGORY, expiration = 3600)
public List<VmCategoryMapper> getVMCategorys(@ParameterValueKeyProvider String code) {
	//get VmCategoryMapper from db
}
Dao中对VmCategoryMapper的读取方法见上面的代码,我们项目中使用了simple-spring-memcached来进行缓存管理。expiration = 3600代表超时时间为1个小时。因为我在服务升级时并没有清理缓存,所以memcached中存在有未超时的缓存对象。这些缓存对象是在升级前存入缓存的,序列化时使用的是原来的默认serialVersionUID也就是1411005385568342784,当服务升级后,由于新的VmCategoryMapper中显示声明了serialVersionUID的值为-235651519180801404,所以如果当查询VmCategoryMapper时,缓存命中,取出memcached中的对象进行反序列化,就会导致serialVersionUID不一致。
定位了原因之后,我把整个memcached进行了flush_all,果然,再也没有抛出该异常了。
这个问题虽然简单,不过还是蛮有意思,值得总结。
分享到:
评论
6 楼 不要叫我杨过 2016-07-25  
定位了原因之后,我把整个memcached进行了flush_all,果然,再也没有抛出该异常了。
5 楼 dongqifan 2015-08-26  
4 楼 qq826928141 2015-06-10  
定位了原因之后,我把整个memcached进行了flush_all,果然,再也没有抛出该异常了。                 我用的hibernate的ehcache  我怎么清理呢????
3 楼 qq826928141 2015-06-10  
定位了原因之后,我把整个memcached进行了flush_all,果然,再也没有抛出该异常了。
2 楼 qq826928141 2015-06-10  
定位了原因之后,我把整个memcached进行了flush_all,果然,再也没有抛出该异常了。                        
1 楼 qq826928141 2015-06-10  
定位了原因之后,我把整个memcached进行了flush_all,果然,再也没有抛出该异常了。

相关推荐

    预警事项:Fastjson反序列化远程代码执行漏洞风险预警

    Fastjson是阿里巴巴的开源JSON解析库,可以解析JSON格式的字符串,支持将Java Bean序列化为JSON字符串,也可以从JSON字符串反序列化到Java Bean。Fastjson接口简单易用,已经被广泛使用在缓存序列化、协议交互、Web...

    JAVA上百实例源码以及开源项目

    ejbCreate函数用于初始化一个EJB实例 5个目标文件,演示Address EJB的实现,创建一个EJB测试客户端,得到名字上下文,查询jndi名,通过强制转型得到Home接口,getInitialContext()函数返回一个经过初始化的上下文,...

    JAVA上百实例源码以及开源项目源代码

    ejbCreate函数用于初始化一个EJB实例 5个目标文件,演示Address EJB的实现,创建一个EJB测试客户端,得到名字上下文,查询jndi名,通过强制转型得到Home接口,getInitialContext()函数返回一个经过初始化的上下文,...

    java面试题

    65. 什么是java序列化,如何实现java序列化? 48 65.1. java序列化、反序列化 48 65.2. 对象的序列化主要有两种用途: 48 65.3. 对象序列化包括如下步骤: 49 65.4. 对象反序列化的步骤如下: 49 66. 反射机制 49 ...

    Java常见面试题208道.docx

    58.什么是 java 序列化?什么情况下需要序列化? 59.动态代理是什么?有哪些应用? 60.怎么实现动态代理? 五、对象拷贝 61.为什么要使用克隆? 62.如何实现对象克隆? 63.深拷贝和浅拷贝区别是什么? 六、Java Web ...

    Java高并发高性能分布式框架从无到有微服务架构设计(1).doc

    使用堆缓存的好处是没有序列化/反序列化,是最快的缓 存.缺点也很明显,当缓存的数据量很大时,GC〔垃圾回收〕暂停时间会变长,存储容量受 限于堆空间大小.一般通过软引用/弱引用来存储缓存对象,即当堆内存不足时,可以...

    java面试题,180多页,绝对良心制作,欢迎点评,涵盖各种知识点,排版优美,阅读舒心

    【基础】Java序列化与反序列化 27 为什么需要序列化与反序列化 28 如何实现Java序列化与反序列化 28 【基础】String s = new String("xyz");创建了几个字符串对象 30 【基础】接口是否可继承(extends)接口?抽象类...

    Java核心面试知识集-Redis面试题

    事务可以理解为一个打包的批量执行脚本,但批量指令并非原子化的操作,中间某条指令的失败不会导致前面已做指令的回滚,也不会造成后续的指令不做。 3. Redis 事务相关命令有哪些? **DISCARD:**取消事务,放弃...

    memcached1

    然后再取出来,并进行名称的修改,然后我们再取这个对象,我们再看其名称,发现修改的对象并不是缓存中的对象,而是通过序列化过来的一个实例对象,这样我们就无须担心对原生类的无意修改导致缓存数据失效了,呵呵~~...

    Java基于Netty实现的高性能分布式IM即时通信系统源码+项目说明.tar

    | Kryo | 序列化协议 | | Leaf-SnowFlake | 利用美团改进的雪花算法生成局部有序的消息id | ## 模块结构 | 模块 | 作用 | | ---------------- | ------------------------------------------------------------ | ...

    工程硕士学位论文 基于Android+HTML5的移动Web项目高效开发探究

    Activity Activity是一个应用程序组件,提供一个屏幕,用户可以用来交互为了完成某项任务,是一个负责与用户交互的组件 SSH 为 Struts+Spring+Hibernate的一个集成框架,是目前较流行的一种Web应用程序开源框架。...

    OpenJPA 2.2.1 API (CHM格式)

    这两个特征,加上 EntityManager 是非序列化的,无法在网络上传输,导致 JPA 应用无法适用于企业应用中的 C/S 实现模式。OpenJPA 扩展了这部分接口,支持数据的远程传输和离线处理。  数据库 / 对象视图统一工具  ...

    Spring Cloud Finchley SR2全套(集成Spring Gateway)

    RedisCacheManager cacheManager = RedisCacheManager.builder(factory) /* 使用自定义的缓存配置初始化一个cacheManager */ .initialCacheNames(cacheNames) /* 注意这两句的调用顺序,一定要先调用该方法设置...

    meta_ws:球衣Springmybatis基本演示

    针对目前各项目代码结构混乱,导致维护难,他人拒绝接收的问题,本人制定出适合本公司现有的JavaWeb技术架构,整理出一个标准的架构。 二、目标 让开发人员只需关注业务逻辑的实现 三、技术框架 基于Jdk1.8 Web控制...

    操作系统(内存管理)

    void free(void *firstbyte):如果给定一个由先前的 malloc 返回的指针,那么该函数会将分配的空间归还给进程的“空闲空间”。 malloc_init 将是初始化内存分配程序的函数。它要完成以下三件事:将分配程序标识为...

    C#微软培训资料

    第三章 编写第一个应用程序 .20 3.1 Welcome 程序 .20 3.2 代 码 分 析 .20 3.3 运 行 程 序 .23 .4 添 加 注 释 .25 3.5 小 结 .27 第二部分 C#程序设计基础.28 第四章 数 据 类 型 .28 4.1 值 类 型...

    freemarker总结

    这是一个典型的分支控制指令,该指令的作用完全类似于Java语言中的if,if指令的语法格式如下: &lt;#if condition&gt;... &lt;#elseif condition&gt;... &lt;#elseif condition&gt;... &lt;#else&gt; ... 例子如下: (age&gt;60)&gt;老年人 ...

    SQLServer2008查询性能优化 2/2

    书名: SQLServer2008查询性能优化 作者: 弗里奇(Grant Fritchey) 出版社: 人民邮电出版社 出版日期: 2010年8月1日 ISBN: 9787115230294 ...12.4.4 可序列化(Serializable) 338 12.4.5 快照(Snapshot) 343 12.5...

    SQLServer2008查询性能优化 1/2

    书名: SQLServer2008查询性能优化 作者: 弗里奇(Grant Fritchey) 出版社: 人民邮电出版社 出版日期: 2010年8月1日 ISBN: 9787115230294 ...12.4.4 可序列化(Serializable) 338 12.4.5 快照(Snapshot) 343 12.5...

Global site tag (gtag.js) - Google Analytics