转载自 深度解析单例与序列化之间的爱恨情仇

本文将通过实例+阅读Java源码的方式介绍序列化是如何破坏单例模式的,以及如何避免序列化对单例的破坏。

单例模式,是设计模式中最简单的一种。通过单例模式可以保证系统中一个类只有一个实例而且该实例易于外界访问,从而方便对实例个数的控制并节约系统资源。如果希望在系统中某个类的对象只能存在一个,单例模式是最好的解决方案。关于单例模式的使用方式,可以阅读单例模式的七种写法

但是,单例模式真的能够实现实例的唯一性吗?

答案是否定的,很多人都知道使用反射可以破坏单例模式,除了反射以外,使用序列化与反序列化也同样会破坏单例。

序列化对单例的破坏 首先来写一个单例的类: code 1

接下来是一个测试类:
code 2

输出结构为false,说明:

通过对Singleton的序列化与反序列化得到的对象是一个新的对象,这就破坏了Singleton的单例性。

这里,在介绍如何解决这个问题之前,我们先来深入分析一下,为什么会这样?在反序列化的过程中到底发生了什么。

ObjectInputStream

对象的序列化过程通过ObjectOutputStream和ObjectInputputStream来实现的,那么带着刚刚的问题,分析一下ObjectInputputStream 的readObject 方法执行情况到底是怎样的。

为了节省篇幅,这里给出ObjectInputStream的readObject的调用栈:

这里看一下重点代码,readOrdinaryObject方法的代码片段:

code 3

上面主要贴出两部分代码。先分析第一部分:

code 3.1

这里创建的这个obj对象,就是本方法要返回的对象,也可以暂时理解为是ObjectInputStream的readObject返回的对象。其生成方式如下:

isInstantiable:如果一个serializable/externalizable的类可以在运行时被实例化,那么该方法就返回true。针对serializable和externalizable我会在其他文章中介绍。

desc.newInstance:该方法通过反射的方式调用无参构造方法新建一个对象。

所以。到目前为止,也就可以解释,为什么序列化可以破坏单例了?

答:序列化会通过反射调用无参数的构造方法创建一个新的对象。

那么,接下来我们再看刚开始留下的问题,如何防止序列化/反序列化破坏单例模式。

防止序列化破坏单例模式

先给出解决方案,然后再具体分析原理:只要在Singleton类中定义readResolve就可以解决该问题。单例的类代码如下:

code 4

继续运行以下测试类:

本次输出结果为true,现在我们的单例就没有被破坏。具体原理,我们回过头继续分析code 3中的第二段代码:

code 3.2

hasReadResolveMethod:如果实现了serializable 或者 externalizable接口的类中包含readResolve则返回true

invokeReadResolve:通过反射的方式调用要被反序列化的类的readResolve方法。

所以,原理也就清楚了,主要在Singleton中定义readResolve方法,并在该方法中指定要返回的对象的生成策略,就可以防止单例被破坏。

深度解析单例与序列化之间的爱恨情仇相关推荐

  1. 一篇讲透Kubernetes与GlusterFS之间的爱恨情仇

    http://rdc.hundsun.com/portal/article/826.html http://rdcqii.hundsun.com/portal/article/827.html 存储是 ...

  2. K8s、Docker、CRI、OCI 之间的爱恨情仇

    一.背景 由于最近知道了 K8s 新版本(v1.20)确定弃用 Docker 的消息,为了明确是否会对现有系统架构产生响,所以对涉及到的相关技术进行了一定的梳理(索性的是对现有的系统架构基本无影响:& ...

  3. 图文直播:Pokémon Go真爱粉与“脑残粉”之间的爱恨情仇

    世界上分为两种人,Pokémon Go玩家和普通游戏玩家. 近来,一款由日本电子游戏业巨头任天堂和美国软件开发公司Niantic联合开发的智能手机游戏"口袋妖怪Go",又名&quo ...

  4. 单例设计模式 序列化破坏单例模式原理解析及解决方案?

    单例设计模式 序列化破坏单例模式原理解析及解决方案? 序列化和反序列化 反射的破坏

  5. 点、线、圆、矩形、抛物线的类定义_点、圆、球和n维球体积之间有怎样的爱恨情仇?让我们一起扒开他们之间鲜为人知,惊为天人的秘密关系!...

    吃瓜群众们,请拿好你们的小板凳,错开坐好,不要挡住后面人的视线,不要把西瓜仔西瓜皮乱吐乱丢.我们要开始了. 恩,让我想想,从何说起. 一个点 如左边所示.试想一下,这个点在纸上变大变大变大,就成了圆. ...

  6. 单例设计模式-序列化破坏单例模式原理解析及解决方案

    越来越成熟了,那是不是坚不可摧的呢,现在我们就要用序列号和反序列化来破坏单例模式,后面也会重点讲一下原理,好好听,让我们来一起破坏单例模式吧,首先还是来到Test类里边 package com.lea ...

  7. java-Transient关键字、Volatile关键字介绍和序列化、反序列化机制、单例类序列化

    - Transient关键字 Java的serialization提供了一种持久化对象实例的机制.当持久化对象时,可能有一个特殊的对象数据成员,我们不想  用serialization机制来保存它.为 ...

  8. iOS之深入解析单例的实现和销毁的底层原理

    一.单例的概念 单例设计模式确保对于一个给定的类只有一个实例存在,这个实例有一个全局唯一的访问点.它通常采用懒加载的方式在第一次用到实例的时候再去创建它. 单例可以保证在程序运行过程,一个类只有一个实 ...

  9. Linux 系统进程、线程之间的爱恨纠葛...

    当一个程序开始执行后,在开始执行到执行完毕退出这段时间内,它在内存中的部分就叫称作一个进程. Linux 是一个多任务的操作系统,也就是说,在同一时间内,可以有多个进程同时执行.我们大家常用的单CPU ...

最新文章

  1. Windows2003利用×××+NAT+静态路由表建立网通电信双线×××服务器
  2. JAVA WEB部分易混淆问题总结
  3. IOS开发之——颜色设置
  4. 黔南民族师范学院计算机与信息学院,黔南民族师范学院
  5. python 随机_python1到3秒随机延时入坑python 心情舒畅
  6. mba学什么书_MBA的完整形式是什么?
  7. windows+PHP+shell_exec()无法执行的原因
  8. Java基础学习总结(158)——开发Leader如何做CodeReview
  9. python自动化办公教程百度云-693629 用Python自动办公,做职场高手(完结)
  10. NYOJ-97兄弟郊游问题
  11. macbook历代_历代MAC机型配置汇总
  12. Jetson AGX Xavier 固态硬盘安装并挂载到/home与无线模块安装
  13. TFS(Taobao File System)团队CODE协作工具
  14. 30分钟写一个聊天板
  15. C2Prog 串口烧录出现Connecting with target… failed(no response)!
  16. mysql主从skip1677_mysql主从复制部署
  17. 渲染器引入KaTeX 模块——实现实时渲染
  18. 学生选课信息系统设计
  19. UVaOJ572---Oil Deposits
  20. k3s 快速入门 - 集群搭建

热门文章

  1. [蓝桥杯][算法提高VIP]摆花-多重背包计数问题
  2. 01tire+洛谷P4551 最长异或路径
  3. Too Many Segments (hard version) CodeForces - 1249D2(贪心+容器vector+set)
  4. word List32
  5. TCP协议——流量控制和拥塞控制
  6. 51 NOD 1363 最小公倍数之和 (欧拉函数思维应用)
  7. HDU - 6975 Forgiving Matching FFT匹配字符串
  8. YBTOJ:彩球抽取(期望)
  9. dfs剪枝:洛谷P2809 hzwer爱折纸
  10. nssl1448-小智过马路【模拟】