深度解析单例与序列化之间的爱恨情仇
轉(zhuǎn)載自?深度解析單例與序列化之間的愛(ài)恨情仇
本文將通過(guò)實(shí)例+閱讀Java源碼的方式介紹序列化是如何破壞單例模式的,以及如何避免序列化對(duì)單例的破壞。
單例模式,是設(shè)計(jì)模式中最簡(jiǎn)單的一種。通過(guò)單例模式可以保證系統(tǒng)中一個(gè)類只有一個(gè)實(shí)例而且該實(shí)例易于外界訪問(wèn),從而方便對(duì)實(shí)例個(gè)數(shù)的控制并節(jié)約系統(tǒng)資源。如果希望在系統(tǒng)中某個(gè)類的對(duì)象只能存在一個(gè),單例模式是最好的解決方案。關(guān)于單例模式的使用方式,可以閱讀單例模式的七種寫法
但是,單例模式真的能夠?qū)崿F(xiàn)實(shí)例的唯一性嗎?
答案是否定的,很多人都知道使用反射可以破壞單例模式,除了反射以外,使用序列化與反序列化也同樣會(huì)破壞單例。
序列化對(duì)單例的破壞 首先來(lái)寫一個(gè)單例的類: code 1 接下來(lái)是一個(gè)測(cè)試類:code 2
輸出結(jié)構(gòu)為false,說(shuō)明:
通過(guò)對(duì)Singleton的序列化與反序列化得到的對(duì)象是一個(gè)新的對(duì)象,這就破壞了Singleton的單例性。
這里,在介紹如何解決這個(gè)問(wèn)題之前,我們先來(lái)深入分析一下,為什么會(huì)這樣?在反序列化的過(guò)程中到底發(fā)生了什么。
對(duì)象的序列化過(guò)程通過(guò)ObjectOutputStream和ObjectInputputStream來(lái)實(shí)現(xiàn)的,那么帶著剛剛的問(wèn)題,分析一下ObjectInputputStream 的readObject?方法執(zhí)行情況到底是怎樣的。
為了節(jié)省篇幅,這里給出ObjectInputStream的readObject的調(diào)用棧:
這里看一下重點(diǎn)代碼,readOrdinaryObject方法的代碼片段:
code 3
上面主要貼出兩部分代碼。先分析第一部分:
code 3.1
這里創(chuàng)建的這個(gè)obj對(duì)象,就是本方法要返回的對(duì)象,也可以暫時(shí)理解為是ObjectInputStream的readObject返回的對(duì)象。其生成方式如下:
isInstantiable:如果一個(gè)serializable/externalizable的類可以在運(yùn)行時(shí)被實(shí)例化,那么該方法就返回true。針對(duì)serializable和externalizable我會(huì)在其他文章中介紹。
desc.newInstance:該方法通過(guò)反射的方式調(diào)用無(wú)參構(gòu)造方法新建一個(gè)對(duì)象。
所以。到目前為止,也就可以解釋,為什么序列化可以破壞單例了?
答:序列化會(huì)通過(guò)反射調(diào)用無(wú)參數(shù)的構(gòu)造方法創(chuàng)建一個(gè)新的對(duì)象。
那么,接下來(lái)我們?cè)倏磩傞_(kāi)始留下的問(wèn)題,如何防止序列化/反序列化破壞單例模式。
防止序列化破壞單例模式先給出解決方案,然后再具體分析原理:只要在Singleton類中定義readResolve就可以解決該問(wèn)題。單例的類代碼如下:
code 4
繼續(xù)運(yùn)行以下測(cè)試類:
本次輸出結(jié)果為true,現(xiàn)在我們的單例就沒(méi)有被破壞。具體原理,我們回過(guò)頭繼續(xù)分析code 3中的第二段代碼:
code 3.2
hasReadResolveMethod:如果實(shí)現(xiàn)了serializable 或者 externalizable接口的類中包含readResolve則返回true
invokeReadResolve:通過(guò)反射的方式調(diào)用要被反序列化的類的readResolve方法。
所以,原理也就清楚了,主要在Singleton中定義readResolve方法,并在該方法中指定要返回的對(duì)象的生成策略,就可以防止單例被破壞。
總結(jié)
以上是生活随笔為你收集整理的深度解析单例与序列化之间的爱恨情仇的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 赛博朋克2077配置设置?
- 下一篇: 对于线程安全的集合类(例如Vector)