java序列化trick and trap

厂内经常出现序列化对象版本不匹配问题,于是发本文说明一些序列化的注意点

调用MQ、memcached、rpc等等涉及到远程通讯的都会经过序列化,虽然客户端透明的封装了细节,但底层是一定会有序列化操作的。因此了解序列化的注意事项是非常有必要的,可以避免误用导致潜在的风险

  • 通过网络传输的对象,必须实现Serializable接口,或者父类已经实现序列化接口。

  • 网络传输对象继承层次不宜过深,封装在内部的对象也不宜太复杂。(太复杂很容易出现某个相关的类没实现序列化接口,而导致整个对象无法序列化)

    • 一般long/int/String/Map/List/Array等常见类组成的对象就 能解决问题
    • 最好不要在本应用对外的业务接口中传递或返回“由另一人或系统主导的业务对象"。因为你不能保证别人的对象版本会兼容,从而导致错误扩散
  • 在接口定义上用的是父类,实际远程传输过去的是子类,反序列化不了的。特别是在rpc中客户端容易出现此问题

  • 远程接口上的参数、返回值类型、会抛出的异常类,都要实现序列化接口。并且server和client都要有对应的类。

    • 一个比较容易忽略的例子是:某服务接口可能会抛出某个运行时异常,但没有把这个异常类放入客户端中,一旦抛出此异常,客户端接收到此异常就会无法反序列化
  • ArrayList.subList()返回的List实现类是内部类型,不能序列化的,通过网络传输会出错。

  • ArrayList经过网络传输后,里面的元素顺序可能不一样

  • 网络传输对象要有无参构造器(如果定义了有参构造器那就要显式定义一个无参构造起),因为机器是不知道传什么内容给有参构造器进行实例化,无参构造器不是public都没关系。没定义无参构造器,有些序列化方式会在底下生成无参构造器的方式才能解决问题。

  • 网络传输最好不要用enum类型,太强耦合,从网络一端传到另一端,对方可能还是旧版本而识别不了。

    • Enum 常量的序列化不同于普通的 serializable 或 externalizable 对象。enum 常量的序列化形式只包含其名称;常量的字段值不被传送。为了序列化 enum 常量,ObjectOutputStream 需要写入由常量的名称方法返回的字符串。
  • 不需通过网络传输的field用transient定义,但有些json序列化类库是不会区别对待这种field

  • 有些序列化类库,遇到反序列化不了的类,会反序列化成Map,但会在使用时遇到class cast异常。

  • 同一应用不要有同package同名的类,可能隐藏在同名/不同名/不同版本的jar中。

serialVersionUID

  • 用于网络传输的对象,第一次上线使用时,就一定要设定serialVersionUID,不要不顾编译警告

    • NOTE: 网络对象的匹配,除了靠类名,还靠serialVersionUID,serialVersionUID在《Java语言规范》有固定算法,跟各field的定义相关,如果没有显式赋值,虽然看不见,但会底下会默认算出一个进行网络传输。

    • 如果没有显式赋值,在看不见觉察不到的情况下,在你增减了field/修改了定义的情况下,serialVersionUID已被改变,这时网络两端就对接不上而悲剧了。

      没定义serialVersionUID,而又发生了serialVersionUID变化,网络两端只有所有机器都停掉,并且先后起有顺序时,才能不出丝毫差错。

  • 最好不要用用1L作为serialVersionUID。0L对于java enum的序列化有特殊意义。

  • 没赋值serialVersionUID 只是警告,不是错误,造成没设定serialVersionUID,网络两端上线运行一段时间也感觉正常。如果再增减修改field,没赋值好serialVersionUID,网络两端就不匹配。

    • 算出旧版本的serialVersionUID(使用serialver或eclipse),设置到新版本的代码中

本文大部分内容取自前同事的分享资料,作了少许修改,外网地址

更多精彩内容请访问首发博客http://jenwang.me

进一步交流:

- Email:jenwang@foxmail.com

- 对于本博客某些话题感兴趣,希望进一步交流的,请加 qq 群:2825967

- 更多技术交流分享在圈子「架构杂谈」,跟老司机们聊聊互联网前沿技术、架构、工具、解决方案等

 

关于serialVersionUID与序列化"的更多相关文章

  1. java 序列化 serialVersionUID 的作用 和 两种添加方式

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

  2. Java 基础 - java序列化 & serialVersionUID

    ref: https://www.cnblogs.com/duanxz/p/3511695.html ------------------- SerialVersionUID概述 SerialVers ...

  3. 一文看懂Java序列化之serialVersionUID

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

  4. serialVersionUID序列化版本号与ObjectOutputStream对象输入输出流

    1. 观察ObjectOutputStream 我们观察ObjectOutputStream就可以发现该类没有无参构造,只有有参构造,所以他是一个包装流 2. 具体使用: public static ...

  5. 序列化之serialVersionUID

    serialVersionUID作用: 序列化时为了保持版本的兼容性,即在版本升级时反序列化仍保持对象的唯一性. 序列化ID起着关键的作用,java的序列化机制是通过在运行时判断类的serialVer ...

  6. Java中的序列化Serialable高级详解

    来自[http://blog.csdn.net/jiangwei0910410003/article/details/18989711] 引言 将 Java 对象序列化为二进制文件的 Java 序列化 ...

  7. Java的序列化ID的作用

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

  8. 黑马程序员_Java基础:序列化(Serializable)与反序列化

    ------- android培训.java培训.期待与您交流! ---------- 在学习IO中的ObjectOutputStream和ObjectInputStream时,会涉及到序列化和反序列 ...

  9. Java序列化的几种方式以及序列化的作用

    Java序列化的几种方式以及序列化的作用 本文着重讲解一下Java序列化的相关内容. 如果对Java序列化感兴趣的同学可以研究一下. 一.Java序列化的作用    有的时候我们想要把一个Java对象 ...

随机推荐

  1. Mac安装的PyCharm找不到顶部菜单栏 PyCharm找不到setting PyCharm不能个性化设置和直接导库

    安装的是最新版的PyCharm,打开发现没有顶部菜单栏,不能直接导库..有点方 以前的就是下面这种 找了很久发现原来在右下角!!!眼拙 点击画圈圈的地方就可以直接进去导库这些啦〜

  2. activity启动模式launchMode区别和优化

    初学android的开发人员,可能会经常忽略这个重要的设置. Activity一共有以下四种launchMode:1.standard2.singleTop3.singleTask4.singleIn ...

  3. 删除eclipse无效的工作空间路径

    eclipse会记录我们使用过的工作空间的路径,方便下面使用.也可以根据自己的需要删除无用的工作空间路径.

  4. 微服务Kong(四)——添加插件

    在本节中,您将学习到,如何配置使用KONG的插件来管理您的API.KONG的核心原则之一就是通过插件来实现API的扩展.插件可以使您更为简单的扩展和管理您的API. 在以下的步骤中,您将通过配置key ...

  5. redis数据类型(五)set类型

    一. set类型 set是无序集合,最大可以包含(2 的 32 次方-1)个元素. set 的是通过 hash table 实现的,所以添加,删除,查找的复杂度都是 O(1). hash table ...

  6. 用尾递归和普通递归实现n!算法,二者比较

    尾递归 - Tail Recursion尾递归是针对传统的递归算法而言的, 传统的递归算法在很多时候被视为洪水猛兽. 它的名声狼籍, 好像永远和低效联系在一起.尾递归就是从最后开始计算, 每递归一次就 ...

  7. Mysql查询今天、昨天、7天、近30天、本月、上一月数据

    今天 SELECT * FROM 表名 WHERE TO_DAYS(时间字段名) = TO_DAYS(now()); 昨天 SELECT * FROM 表名 WHERE TO_DAYS( NOW( ) ...

  8. C《二》

    开始阅读谭浩强的C语言程序设计. 编译一个程序,除了语法以外,还需要管理内存,就是数据结构,学习如何高效的利用内存:数据关系的处理.例如学生管理系统的开发,但是数据关系是有最优解的,也就是可以学会的, ...

  9. 信号量 P V测试详解

    信号量 当我们编写的程序使用了线程时,不管它是运行在多用户系统上,多进程系统上,还是运行在多用户多进程系统上,我们通常会发现,程序中存在着一部分临界代码,我们需要确保只有一个进程可以进入这个临界代码并 ...

  10. ASP.NET 简单的柱形图实现(附带示例)

    对于一些内部系统的项目,各种图表是在所难免的,因为图表可以更加清晰的表达出想看到的数据. 因为之前从来没有做过关于图表的东西,唯一能想到的就是“验证码”,所以应该是一个思路,用GDI去搞. 数据懒着去 ...