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

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

本文将通过实例+阅读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方法,并在该方法中指定要返回的对象的生成策略,就可以防止单例被破坏。


本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/329833.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Windows 10中国定制版完工!更专业

去年底,微软与中国电子科技网络信息安全有限公司成立了一个合资公司,该公司的主要任务是为中国政府和企业定制 Windows 10 系统。 现在,微软大中华区董事长兼CEO贺乐赋在接受财新网记者采访时表示,微软与中国电子科技集团公司&…

Spring [CVE-2022-22965]漏洞处理

问题描述 近期spring官方公布了漏洞 - [CVE-2022-22965] 参考地址: https://tanzu.vmware.com/security/cve-2022-22965 参考issues提到的问题答案开发人员回应: 可能是由于Springframework 3.x 早于 JDK9发布,甚至发布时还未完整的支持JDK…

kafak消费者从头开始消费(消费者组)

【README】 本文主要用于描述 kafka 消费者如何从头开始消费; 【1】从头开始消费 1)从头开始消费,需要满足两个条件, 如下: 条件1, 使用一个全新的消费者组id;条件2,指定 auto.of…

jenkins安装与配置windows_Windows下Scoop安装、配置与使用

Scoop简介Scoop是Windows的命令行安装程序,是一个强大的包管理工具。可以在github上找到其项目的相关信息,项目网址。安装的起因:在平常生活中如果要安装像gcc、git等一些需要手动配置相关参数的工具,需要先去官网下载安装程序&am…

对于线程安全的集合类(例如Vector)的任何操作是不是都能保证线程安全

转载自 对于线程安全的集合类(例如Vector)的任何操作是不是都能保证线程安全之前在公众号中问了这个问题:对于线程安全的集合类(例如Vector)的任何操作是不是都能保证线程安全? 三天之内收到120回复&#x…

ASP.NET Core 1.0中的管道-中间件模式

ASP.NET Core 1.0借鉴了Katana项目的管道设计(Pipeline)。日志记录、用户认证、MVC等模块都以中间件(Middleware)的方式注册在管道中。显而易见这样的设计非常松耦合并且非常灵活,你可以自己定义任意功能的Middleware注册在管道中。这一设计非常适用于“请求-响应”…

怎么样安装Ubuntu系统,一文告诉你

前言 额滴神呐/(ㄒoㄒ)/~~,用惯了windows开发,初上手Linux桌面开发真的是举步维艰(内心ps:谁让你立这个标题的,现在后悔了吧… 你自己想办法 怎么把这个标题栏目圆过去) 经过跟内心戏反复的都在&#xff0…

(转) SpringBoot接入两套kafka集群

转自: SpringBoot接入两套kafka集群 - 风小雅 - 博客园引入依赖 compile org.springframework.kafka:spring-kafka 第一套kafka配置 package myapp.kafka; importhttps://www.cnblogs.com/ylty/p/13673357.html 引入依赖 compile org.springframework.kafka:spring…

idea tomcat部署web项目_项目开发之部署帆软到Tomcat服务一

书接上回上一篇文章介绍了两种图表取数的方式,新增数据库查询和通过存储过程取数,其他的内置数据集,文件数据集和关联数据集等方式暂时还没有用到,先暂时不介绍了,等之后用到了或者等小编有时间试过之后再来做个简单的…

C#工业物联网和集成系统解决方案的技术路线

前言 2000年以后,互联网在中国的大地上如火如荼的发展,在这个行业竞争中比的是加速度。我清晰的记得《世界是平的》中有这样一段话:在非洲,羚羊每天早上醒来时,它知道自己必须跑得比最快的狮子还快,否则就会…

转:Kafka事务使用和编程示例/实例

Kafka事务使用和编程示例/实例_JobShow裁员加班实况-微信小程序-CSDN博客一、概述​ Kafka事务特性是指一系列的生产者生产消息和消费者提交偏移量的操作在一个事务中,或者说是一个原子操作,生产消息和提交偏移量同时成功或者失败。注意:kafk…

[初级]Java中的switch对整型、字符型、字符串的具体实现细节

转载自 [初级]Java中的switch对整型、字符型、字符串的具体实现细节Java 7中,switch的参数可以是String类型了,这对我们来说是一个很方便的改进。到目前为止switch支持这样几种数据类型:byteshort int char String 。但是,作为一个…

SpringBoot-Cache整合redis

前言 SpringBoot的众多Starter有两个很重要的缓存Starter,其中一个是我们经常用到的Redis(spring-boot-starter-data-redis)还有一个是 spring-boot-starter-cache。 今天主要是简单介绍一个如何整合这两个组件,达到相互合作的关系…

C#跨平台物联网通讯框架ServerSuperIO(SSIO)

一.SSIO的特点 轻型高性能通信框架,适用于多种应用场,轮询模式、自控模式、并发模式和单例模式。设备驱动、IO通道、控制模式场景协调统一。设备驱动内轩命令驱动器、命令缓存器、自定义参数和实时数据元素。框架平台支持按设备命令优先级别进行调度&…

spring boot 单元测试_spring-boot-plus1.2.0-RELEASE发布-快速打包-极速部署-在线演示

spring-boot-plusspring-boot-plus集成spring boot常用开发组件的后台快速开发脚手架Purpose每个人都可以独立、快速、高效地开发项目!Everyone can develop projects independently, quickly and efficiently!官网地址:springboot.plusGITHU…

在Java中如何高效的判断数组中是否包含某个元素

转载自 在Java中如何高效的判断数组中是否包含某个元素如何检查一个数组(无序)是否包含一个特定的值?这是一个在Java中经常用到的并且非常有用的操作。同时,这个问题在Stack Overflow中也是一个非常热门的问题。在投票比较高的几个答案中给出了几种不同的…

spring-kafka整合:DefaultKafkaProducerFactory默认kafka生产者工厂介绍

【README】 0,为啥要看 DefaultKafkaProducerFactory? 最近在基于 springboot 开发kafka模块,发现 kafakTemplate构造器传入了 DefaultKafkaProducerFactory实例, kafkaTemplate内部使用了 很多 DefaultKafkaProducerFactory的方…

【SpringSecurity】【JJWT】JJWT踩坑LocalDateTime

前言 最近自己又在开始闲搞&#xff0c;主要原因还是下山无望&#xff08;买显卡&#xff09;。只能晚上下班找点事情做啦~~ 环境 版本请根据实际情况参考JJWT官网选择使用&#xff0c;这里只说明一下问题大概思路&#xff01; <!-- 增加token生成依赖 --> <depen…

针对Linux ASP.NET MVC网站中 httpHandlers配置无效的解决方案

近期有Linux ASP.NET用户反映&#xff0c;在MVC网站的Web.config中添加 httpHandlers 配置用于处理自定义类型&#xff0c;但是在运行中并没有产生预期的效果&#xff0c;服务器返回了404&#xff08;找不到网页&#xff09;错误。经我亲自测试&#xff0c;在WebForm网站中&…

简单介绍Java中Comparable和Comparator

转载自 简单介绍Java中Comparable和ComparatorComparable 和 Comparator是Java核心API提供的两个接口&#xff0c;从它们的名字中&#xff0c;我们大致可以猜到它们用来做对象之间的比较的。但它们到底怎么用&#xff0c;它们之间有又哪些差别呢&#xff1f;下面有两个例子可以…