你知道的越多,不知道的就越多,业余的像一棵小草!

成功路上并不拥挤,因为坚持的人不多。

编辑:业余草

juejin.cn/post/6961229793056686117

推荐:https://www.xttblog.com/?p=5219

公司有个子服务较多,交互频繁的系统,有一些需要共享传输的对象,它们通过 JDK 序列化(Java Object Serialization)后进行交互;但是由于一些不可描述的历史原因,这些对象存在多个版本,每个版本中的属性不一致,且未设置 serialVersionUID

这阵子在做梳理/统一代码的工作,打算统一这些对象的版本和固定 serialVersionUID,但是由于服务较多,上线发版时会有一段新老版本共存的时期,所以得考虑这些对象序列化的兼容问题,新的对象反序列化一定得兼容老的对象。

Java Object Serialization

Java对象序列化(Serialization)是指将Java中的对象转为字节流,从而可以方便的存储或在网络中传输,反序列化(Deserialization)是指将字节流转位Java对象

一般情况下,Java Object Serialization指的是利用JDK自带的功能对对象进行序列化/反序列化,而不是使用其他的序列化库进行(反)序列化

JDK 序列化中,要求对象必须实现java.io.Serializable接口,基本使用方式如下:

Serialization

// Serialize today's date to a file.
FileOutputStream f = new FileOutputStream("tmp");
ObjectOutput s = new ObjectOutputStream(f);
s.writeObject("Today");
s.writeObject(new Date());
s.flush();

Deserialization

// Deserialize a string and date from a file.
FileInputStream in = new FileInputStream("tmp");
ObjectInputStream s = new ObjectInputStream(in);
String today = (String)s.readObject();
Date date = (Date)s.readObject();

serialVersionUID

private static final long serialVersionUID = 1L;

Java Object Serialization 会使用对象中的 serialVersionUID 常量属性作为该对象的版本号,进行反序列化时会校验该版本号是否一致,如果不一致会导致序列化失败,抛出InvalidClassException异常

默认情况下,JVM 为每一个实现了 Serializable 的接口的类生成一个 serialVersionUID(long),这个 ID 的计算规则是通过当前类信息(类名、属性等)去生成的,所以当属性有变更时这个serialVersionUID 也一定会发生变更

这个 serialVersionUID 的生成,和所使用的JDK有关,不同的JDK可能会生成不一样的版本号,所以最好是手动生成一个,大多数 JAVA IDE 都会提供这个生成的功能。

而且考虑到实际业务场景,变更属性是常有的事,如果使用自动生成的版本号很容易造成 serialVersionUID 不一致的问题,导致反序列化失败

serialVersionUID 不一致兼容处理

处理这个不一致也很简单,既然反序列化时使用 ObjectInputStream 来实现,那么这里自定义一个 CompatibleInputStream 继承 ObjectInputStream,然后重写 readClassDescriptor 方法即可

当遇到目标数据 Class 版本号和本地 Class 版本号不一致时,默认使用本地版本的 Class

public class CompatibleInputStream extends ObjectInputStream {private static Logger logger = LoggerFactory.getLogger(CompatibleInputStream.class);public CompatibleInputStream(InputStream in) throws IOException {super(in);}@Overrideprotected ObjectStreamClass readClassDescriptor() throws IOException, ClassNotFoundException {ObjectStreamClass resultClassDescriptor = super.readClassDescriptor(); // initially streams descriptorClass localClass; // the class in the local JVM that this descriptor represents.try {localClass = Class.forName(resultClassDescriptor.getName()); } catch (ClassNotFoundException e) {logger.error("No local class for " + resultClassDescriptor.getName(), e);return resultClassDescriptor;}ObjectStreamClass localClassDescriptor = ObjectStreamClass.lookup(localClass);if (localClassDescriptor != null) { // only if class implements serializablefinal long localSUID = localClassDescriptor.getSerialVersionUID();final long streamSUID = resultClassDescriptor.getSerialVersionUID();if (streamSUID != localSUID) { // check for serialVersionUID mismatch.final StringBuffer s = new StringBuffer("Overriding serialized class version mismatch: ");s.append("local serialVersionUID = ").append(localSUID);s.append(" stream serialVersionUID = ").append(streamSUID);Exception e = new InvalidClassException(s.toString());logger.error("Potentially Fatal Deserialization Operation.", e);resultClassDescriptor = localClassDescriptor; // Use local class descriptor for deserialization}}return resultClassDescriptor;}
}

以上关键代码摘自

https://stackoverflow.com/a/1816711/6507948

使用方式:

// Deserialize a string and date from a file.
FileInputStream in = new FileInputStream("tmp");
//反序列化时使用上面的CompatibleInputStream即可
ObjectInputStream s = new CompatibleInputStream(in);
String today = (String)s.readObject();
Date date = (Date)s.readObject();

欢迎留言评论你曾遇到过的序列化bug,以及你是怎么被坑的!

Java序列化,碰到serialVersionUID不一致怎么处理?相关推荐

  1. Java序列化之serialVersionUID

    Java序列化之serialVersionUID 今天讲一讲Java对象中的serialVersionUID,先从序列化讲起. 什么是序列化 序列化,简单的说,就是将一个对象转化(编码)成可以传输的输 ...

  2. JDK 序列化, 碰到serialVersionUID 不一致问题,怎么处理?

    以下文章来源方志朋的博客,回复"666"获面试宝典 公司有个子服务较多,交互频繁的系统,有一些需要共享传输的对象,它们通过 JDK 序列化(Java Object Serializ ...

  3. 探析“Java序列化”之serialVersionUID

    未显式指定serialVersionUID 当没有显式地定义serialVersionUID变量时,Java序列化机制会根据编译的class自动生成一个serialVersionUID作序列化版本,它 ...

  4. java 序列化 uid_一文看懂Java序列化之serialVersionUID

    serialVersionUID适用于Java的序列化机制.简单来说,Java的序列化机制是通过判断类的serialVersionUID来验证版本一致性的.在进行反序列化时,JVM会把传来的字节流中的 ...

  5. hessian java_Hessian和java序列化对比

    java的序列化 ​1.Java序列化的性能经常被吐槽. 2.Java序列化后的数据相对于一些优秀的序列化的工具,还是要大不少,比如probuf,这大大影响存储和传输的效率. 3.Java序列化一定需 ...

  6. java 四字节uid,Java入门教程-序列化版本号serialVersionUID的作用

    原标题:Java入门教程-序列化版本号serialVersionUID的作用 Java序列化是将一个对象编码成一个字节流,反序列化将字节流编码转换成一个对象.序列化是Java中实现持久化存储的一种方法 ...

  7. Java对象的serialVersionUID在序列化和反序列化的用途

    本博客主要转自如下链接 http://blog.csdn.net/javazejian/article/details/52665164 这篇文章写的不错,但是有些地方我估计博主没有亲自测试,所以有些 ...

  8. java 序列化版本号_序列化版本号serialVersionUID的作用

    原标题:序列化版本号serialVersionUID的作用 Java序列化是将一个对象编码成一个字节流,反序列化将字节流编码转换成一个对象.序列化是Java中实现持久化存储的一种方法:为数据传输提供了 ...

  9. 色谈Java序列化:女孩子慎入 - 第280篇

    优美格式地址:https://mp.weixin.qq.com/s/8tcHFjY1VawAkzdArkSzJQ 悟纤:师傅,最近我老是碰到一个异常:java.io.NotSerializableEx ...

最新文章

  1. 浅析电商、社区、游戏常用的 MySQL 架构
  2. 使用CSS制作圆角效果
  3. 无需「域外」文本,微软:NLP就应该针对性预训练
  4. Android 解决RecyclerView删除Item导致位置错乱的问题
  5. 【项目实践】【01】发货管理系统 SPS (2007年12月23日更新)
  6. jeecms内容管理系统使用了哪些技术
  7. 2.6.2.MySQL主从复制的原理
  8. 跟我一起学WCF(2)——利用.NET Remoting技术开发分布式应用
  9. 几个超级实用但很少人知道的 VS 技巧[更新]
  10. mysql用any查询_mysql 5.6有ANY_VALUE功能吗?
  11. 如何针对业务设计架构?——QCon热点专题前瞻
  12. 百面机器学习—11.集成学习(GBDT、XGBoost)面试问题总结
  13. 论文笔记_SLAM_综述十几篇_目录
  14. LVS-DR工作原理图文详解(转载)
  15. zabbix监控系统--详细安装教程
  16. 带有打开密码的压缩包如何解压
  17. 微信支付sdk部署在服务器,android接入微信支付SDK
  18. LaTeX中文生僻字显示
  19. 怎么用python做自动化测试?
  20. 【Python黑科技】tkinter库实战“贪吃蛇”小游戏(保姆级图文+实现代码)

热门文章

  1. 项目进度控制的主要任务是什么?
  2. 工程项目进度控制的重点内容是什么?
  3. cvat标注软件入门
  4. 微信公众号订阅通知(go+vue)
  5. 指纹登录 TouchID FaceID
  6. 数组的entries()方法
  7. 场景编程集锦 - BMI指数与健身达人
  8. 数字图像处理100问—03二值化(Thresholding)
  9. 机器学习在信息安全领域的应用现状和畅想
  10. 微信公众号java开发沉淀(五)推送群发消息