单例设计模式-序列化破坏单例模式原理解析及解决方案
生活随笔
收集整理的這篇文章主要介紹了
单例设计模式-序列化破坏单例模式原理解析及解决方案
小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.
越來(lái)越成熟了,那是不是堅(jiān)不可摧的呢,現(xiàn)在我們就要用序列號(hào)和反序列化來(lái)破壞單例模式,后面也會(huì)重點(diǎn)講一下原理,好好聽(tīng),讓我們來(lái)一起破壞單例模式吧,首先還是來(lái)到Test類里邊
package com.learn.design.pattern.creational.singleton;import java.io.Serializable;/*** 我們讓他來(lái)實(shí)現(xiàn)序列號(hào)接口* 具體序列話和反序列化的版本號(hào)呢* 我們就不關(guān)注了* 因?yàn)檫@個(gè)不是重點(diǎn)* * 我們現(xiàn)在的HungrySingleton實(shí)現(xiàn)了Serializable接口* 那么在ObjectStreamClass這里邊* 判斷就會(huì)返回true* boolean isInstantiable() {* requireInitialized();* return (cons != null);* }* 返回true之后再回來(lái)* * @author Leon.Sun**/
public class HungrySingleton implements Serializable,Cloneable{private final static HungrySingleton hungrySingleton;static{hungrySingleton = new HungrySingleton();}private HungrySingleton(){if(hungrySingleton != null){throw new RuntimeException("單例構(gòu)造器禁止反射調(diào)用");}}public static HungrySingleton getInstance(){return hungrySingleton;}/*** 我們寫(xiě)一個(gè)方法* 返回一個(gè)Object* * 從override里面根本就沒(méi)有* 他根本就不是Object的方法* 那方法為什么又叫readResolve呢* 叫別的名字可不可以呢* 那我們就較真* 為什么要這么寫(xiě)* * * @return*/private Object readResolve(){/*** 然后在這里面返回一個(gè)單例對(duì)象* 我們回到Test里邊* 我們直接再run一下* 咱們一起來(lái)看* 最后看是否相等呢* 最后返回true* 這就很神奇了* 回到這個(gè)單例類里面* 你們肯定有一個(gè)疑問(wèn)* 你為什么寫(xiě)這個(gè)方法啊* * * */return hungrySingleton;}@Overrideprotected Object clone() throws CloneNotSupportedException {return getInstance();}
}
package com.learn.design.pattern.creational.singleton;import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InvalidClassException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.ObjectStreamClass;
import java.lang.reflect.Constructor;
import java.lang.reflect.Executable;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;/*** 我們已經(jīng)確定單例模式只能獲取一個(gè)對(duì)象* 就使用HungrySingleton這個(gè)類作為測(cè)試* * * @author Leon.Sun**/
public class Test {public static void main(String[] args) throws IOException, ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
// LazySingleton lazySingleton = LazySingleton.getInstance();// System.out.println("main thread"+ThreadLocalInstance.getInstance());
// System.out.println("main thread"+ThreadLocalInstance.getInstance());
// System.out.println("main thread"+ThreadLocalInstance.getInstance());
// System.out.println("main thread"+ThreadLocalInstance.getInstance());
// System.out.println("main thread"+ThreadLocalInstance.getInstance());
// System.out.println("main thread"+ThreadLocalInstance.getInstance());// Thread t1 = new Thread(new T());
// Thread t2 = new Thread(new T());
// t1.start();
// t2.start();
// System.out.println("program end");/*** 從這里面拿了一個(gè)對(duì)象來(lái)* 那這個(gè)單例對(duì)象我們拿到了* 現(xiàn)在我們想象一下* 如果我們把這個(gè)instance序列號(hào)到一個(gè)文件中* 然后再?gòu)奈募锶〕鰜?lái)* 那這兩個(gè)對(duì)象還是同一個(gè)對(duì)象嗎* 那現(xiàn)在我們就來(lái)測(cè)試一下* * 首先單例獲取一個(gè)對(duì)象* * */HungrySingleton instance = HungrySingleton.getInstance();
// EnumInstance instance = EnumInstance.getInstance();
// instance.setData(new Object());
///*** 我們直接用ObjectOutputStream流* oos就是ObjectOutputStream三個(gè)字母的首字母小寫(xiě)* new一個(gè)ObjectOutputStream* 里面new一個(gè)FileOutputStream* 名字我們起一個(gè)名字就叫singleton_file* 這個(gè)時(shí)候這里爆紅了* 應(yīng)該是異常* 我們也不try catch了* 我們直接拋出* 然后呢繼續(xù)* * 看一下我們使用的類ObjectOutputStream* * 然后序列號(hào)* */ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("singleton_file"));/*** 我們通過(guò)ObjectOutputStream對(duì)象寫(xiě)一下* * */oos.writeObject(instance);
///*** 現(xiàn)在我們?cè)僮x一下他* new一個(gè)File* 文件名singleton_file* * */File file = new File("singleton_file");/*** 我們?cè)偻ㄟ^(guò)ObjectInputStream讀取這個(gè)文件* 里面再放一個(gè)FileInputStream* 把這個(gè)file放進(jìn)來(lái)* 這個(gè)時(shí)候我們通過(guò)ObjectInputStream獲取的這個(gè)對(duì)象去讀取他* 和上面聲明的instance做一個(gè)對(duì)比* 判斷他們是不是同一個(gè)對(duì)象* * ObjectInputStream* 我們重點(diǎn)看一下ois這個(gè)對(duì)象* 也就是ObjectInputStream這個(gè)類的對(duì)象* 他的readObject方法* 我們進(jìn)來(lái)看一下* 看一下這個(gè)方法* 從上往下看* 重點(diǎn)看一下Object obj = readObject0(false);這一行的代碼* 他又調(diào)用readObject0這個(gè)方法* 我們進(jìn)來(lái)看一下* private Object readObject0(boolean unshared)* 這個(gè)就是讀取對(duì)象* 各種邏輯不是我們要講的重點(diǎn)* 我們往下看* 這里面有一個(gè)switch* switch (tc)* 讀對(duì)應(yīng)的類型* TC_STRING* TC_LONGSTRING* TC_ARRAY* TC_ENUM* TC_OBJECT* 那我們的是什么呢* 肯定是Object* TC_OBJECT* 所以我們的代碼會(huì)走到return checkResolve(readOrdinaryObject(unshared));這一行* 然后我們看一下他調(diào)的方法* 這一行調(diào)了兩個(gè)方法* 首先調(diào)了readOrdinaryObject這個(gè)方法* 然后把返回值放入checkResolve方法* 我們先進(jìn)入readOrdinaryObject這個(gè)方法* private Object readOrdinaryObject(boolean unshared)* 往下看* 上面還是各種判斷校驗(yàn)* 這里可以看到* if (cl == String.class || cl == Class.class* || cl == ObjectStreamClass.class) {* throw new InvalidClassException("invalid class descriptor");* }* 如果是String,* Class或者ObjectClass* 就會(huì)報(bào)一個(gè)異常* 無(wú)效的class* Object obj;* 然后我們看一下obj = desc.isInstantiable() ? desc.newInstance() : null;這一行* 這里面做了一個(gè)判斷* 首先我們看一下obj這個(gè)Object對(duì)象* 然后往下走* 看看他做什么用* return obj;* 我們看到把它返回回去了* 接著回來(lái)* 那我們就看這一行* obj = desc.isInstantiable() ? desc.newInstance() : null* 這里面做了一個(gè)判斷* 如果isInstantiable這個(gè)返回的是true的話* 就會(huì)生成一個(gè)新的對(duì)象* 否則返回null* 這個(gè)就是從readObject傳進(jìn)來(lái)的* 所以我們看一下* isInstantiable()這個(gè)方法是做什么用的* 這里呢很簡(jiǎn)單* boolean isInstantiable() {* requireInitialized();* return (cons != null);* }* return cons不等于空* cons是什么呢* private Constructor<?> cons;* 也就是反射的構(gòu)造器類型* public final class Constructor<T> extends Executable* 回來(lái)* 從這行代碼看不出什么* 那這個(gè)時(shí)候我們就得看注釋了* 還好我們有注釋可以看* 這個(gè)注釋意思是說(shuō)* Returns true if represented class is serializable/externalizable and can* 我們看一下serializable/externalizable* 包括下面還有be instantiated by the serialization runtime--i.e., if it is* 簡(jiǎn)單的說(shuō)呢* 如果serializable或者externalizable* 如果這樣的一個(gè)類class* 正在運(yùn)行時(shí)被實(shí)例化* 那么該方法就會(huì)返回true* 所以returns true* 那這兩個(gè)序列化方式* serializable這個(gè)是比較全的* 而externalizable這個(gè)是定制哪些字段* 都可以通過(guò)它來(lái)定制* 那么看一下這個(gè)類* 他又繼承serializable* 他作為接口又是serializable的子類* 而我們平時(shí)實(shí)現(xiàn)的都是serializable這個(gè)類* 那平時(shí)定制序列號(hào)的情況* 也比較少見(jiàn)* 那就好理解了* 我們現(xiàn)在的HungrySingleton實(shí)現(xiàn)了Serializable接口* 那么在ObjectStreamClass這里邊* 判斷就會(huì)返回true* boolean isInstantiable() {* requireInitialized();* return (cons != null);* }* 返回true之后再回來(lái) * obj = desc.isInstantiable() ? desc.newInstance() : null;* isInstantiable他為true的話就會(huì)newInstance* 然后把obj返回回去* 到這兒就比較清晰了* 這個(gè)對(duì)象是通過(guò)反射創(chuàng)建出來(lái)的對(duì)象* newInstance* ObjectStreamClass desc = readClassDesc(false);* desc是ObjectStreamClass類型的* 既然通過(guò)反射去創(chuàng)建對(duì)象* 那肯定和之前的對(duì)象不是同一個(gè)* 這也就是解釋了我剛剛為什么序列化和反序列化單例模式破壞了* 那到這里之后啊* 還是沒(méi)有找到我們想要的答案* 我們接著往下看* if (obj != null &&* handles.lookupException(passHandle) == null &&* desc.hasReadResolveMethod()) * 判斷obj不會(huì)為空* 然后進(jìn)行一系列的判斷* 然后深入進(jìn)去看了* 然后看看hasReadResolveMethod這個(gè)* 從這個(gè)名字就能夠看出來(lái)* 判斷它是否有ReadResolve方法* 我們進(jìn)來(lái)看一下* boolean hasReadResolveMethod() {* requireInitialized();* return (readResolveMethod != null);* }* 這個(gè)也很簡(jiǎn)單* 我們首先看一下這個(gè)對(duì)象* 他就是一個(gè)Method* private Method readResolveMethod;* return (readResolveMethod != null);* 也就是這一行通過(guò)源碼看不出什么* 那我們就看注釋* 注釋很有用* 平時(shí)看源碼的時(shí)候一定要養(yǎng)成看注釋的好習(xí)慣* Returns true if represented class is serializable or externalizable and* 返回true* 如果這個(gè)類是serializable這個(gè)接口或者externalizable這個(gè)接口類型* 實(shí)現(xiàn)了這個(gè)接口那class自然也是這個(gè)類型* and還有一個(gè)條件* defines a conformant readResolve method. Otherwise, returns false.* 那這個(gè)注釋已經(jīng)說(shuō)得很清楚了* 我們回來(lái)* 因?yàn)榕段覀兌x了這個(gè)方法* 所以desc.hasReadResolveMethod()這里判斷剩下* 那怎么調(diào)用那個(gè)方法呢* Object rep = desc.invokeReadResolve(obj);* 把obj傳進(jìn)來(lái)* 進(jìn)來(lái)看一下* 很明顯通過(guò)這個(gè)名字就能夠看出來(lái)* 它是通過(guò)反射來(lái)調(diào)用invokeReadResolve方法的* return readResolveMethod.invoke(obj, (Object[]) null);* 也就是說(shuō)這個(gè)時(shí)候調(diào)用HungrySingleton里面寫(xiě)的readResolve方法* 那么再回到ObjectStreamClass里邊* return readResolveMethod.invoke(obj, (Object[]) null);* 這個(gè)就是反射方法* 那這個(gè)方法名在哪里定義的呢* 抱著這個(gè)好奇心搜索這個(gè)關(guān)鍵字* readResolveMethod = getInheritableMethod(* cl, "readResolve", null, Object.class);* readObjectMethod賦值成什么呢* 名字賦成readResolve* readResolve他就是我們剛剛寫(xiě)的目標(biāo)方法名* 就在這里* 終于找到他了* 具體這個(gè)源碼怎么看呢* 我會(huì)debug根據(jù)源碼里面一行一行看一下* 你們也可以去看源碼* 這個(gè)是學(xué)習(xí)框架和源碼非常好的一種方式* 那回來(lái)* 所以這個(gè)方法是通過(guò)反射出來(lái)的* 也沒(méi)什么繼承關(guān)系* 所以只能把這個(gè)方法直接寫(xiě)到這里* 一起來(lái)debug一下* 看源碼的時(shí)候也要看關(guān)鍵點(diǎn)* 現(xiàn)在一起debug一下* 我們跟一遍源碼* * 反序列化出來(lái)* */ObjectInputStream ois = new ObjectInputStream(new FileInputStream(file));
///*** 強(qiáng)轉(zhuǎn)把異常拋出* * 這個(gè)時(shí)候可以調(diào)用readObject方法* 然后進(jìn)入readObject0* 我們?cè)俅蛞粋€(gè)斷點(diǎn)* 之后就來(lái)到這里了* 我們看一下我們剛剛關(guān)注的Object這個(gè)case* case TC_OBJECT:* 看到進(jìn)入到return checkResolve(readOrdinaryObject(unshared));* 然后readOrdinaryObject這個(gè)方法* 下邊繼續(xù)* obj = desc.isInstantiable() ? desc.newInstance() : null;* 我們看一下desc.isInstantiable()他的返回值是什么* 正如我們的預(yù)期他的返回值是true* 所以他會(huì)調(diào)一個(gè)newInstance* 我們單步走一下* 這個(gè)時(shí)候我們?cè)趦?nèi)存里面看一下obj* Object obj;* 我們看到這個(gè)對(duì)象其實(shí)已經(jīng)new出來(lái)了* HungrySingleton* 后面我記得還有一個(gè)斷點(diǎn)F8* desc.hasReadResolveMethod()* 判斷方法有沒(méi)有* 看來(lái)進(jìn)入了if* Object rep = desc.invokeReadResolve(obj);* 開(kāi)始invoke這個(gè)方法了* 進(jìn)來(lái)* 注意if (readResolveMethod != null)這個(gè)* F8過(guò)來(lái)* 判斷他是不是空* 我們打開(kāi)看一下* 這個(gè)Method類型* 可以看到name是readResolve* 他并不是空* 所以F6單步* return readResolveMethod.invoke(obj, (Object[]) null);* 這個(gè)時(shí)候反射調(diào)用這個(gè)方法* 會(huì)到HungrySingleton類里邊* private Object readResolve()* 這個(gè)時(shí)候就有了* F8這個(gè)時(shí)候* return hungrySingleton;* 這個(gè)時(shí)候就調(diào)用了這個(gè)方法* 而hungrySingleton這個(gè)對(duì)象我們看一下* 他本身已經(jīng)創(chuàng)建好了* 是420* 而這個(gè)時(shí)候* return的時(shí)候* 就把這個(gè)對(duì)象返回回去了* 而不會(huì)剛剛通過(guò)反射newInstance* 這個(gè)時(shí)候return obj;* 返回的是hungrySingleton 420* 也就是HungrySingleton這里面的對(duì)象* F8繼續(xù)* 下邊我們就不看了* 剛剛講的這一串呢* 是序列號(hào)和反序列化的一個(gè)重點(diǎn)* 核心* 現(xiàn)在F8直接過(guò)* 回到Test里面看console一模一樣* 可是有一點(diǎn)* 我們考慮一下* 雖然最終返回的是同一個(gè)對(duì)象了* 但是在這個(gè)過(guò)程中* 其實(shí)它實(shí)例化對(duì)象了* 只是最后返回沒(méi)有返回而已* 所以一旦我們的業(yè)務(wù)場(chǎng)景涉及序列化和反序列化的時(shí)候* 一定要注意對(duì)單例的破壞* 這個(gè)呢非常重要* 希望通過(guò)這個(gè)能對(duì)序列化和反序列化單例的破壞有一個(gè)深入的理解* 并且學(xué)會(huì)如何看源碼* 如何找源碼的關(guān)鍵路徑* 這些技能對(duì)成長(zhǎng)是非常有益處的* 我們接下來(lái)看一下對(duì)于反射這種情況* 我們?nèi)绾蝸?lái)防御呢* * * */HungrySingleton newInstance = (HungrySingleton) ois.readObject();
// EnumInstance newInstance = (EnumInstance) ois.readObject();
//
// System.out.println(instance.getData());
// System.out.println(newInstance.getData());
// System.out.println(instance.getData() == newInstance.getData());// Class objectClass = HungrySingleton.class;
// Class objectClass = StaticInnerClassSingleton.class;// Class objectClass = LazySingleton.class;
// Class objectClass = EnumInstance.class;// Constructor constructor = objectClass.getDeclaredConstructor(String.class,int.class);
//
// constructor.setAccessible(true);
// EnumInstance instance = (EnumInstance) constructor.newInstance("Geely",666);//
// LazySingleton newInstance = (LazySingleton) constructor.newInstance();
// LazySingleton instance = LazySingleton.getInstance();// StaticInnerClassSingleton instance = StaticInnerClassSingleton.getInstance();
// StaticInnerClassSingleton newInstance = (StaticInnerClassSingleton) constructor.newInstance();// HungrySingleton newInstance = (HungrySingleton) constructor.newInstance();
// HungrySingleton instance = HungrySingleton.getInstance();/*** 在判斷之前呢* 我們把這個(gè)兩個(gè)對(duì)象都輸出一下* 我們r(jià)un一下* 這里面會(huì)拋一個(gè)異常* 這個(gè)異常我們看到就知道了* 這里的異常說(shuō)了* 不是可序列化的異常* 很簡(jiǎn)單* 我們讓他來(lái)實(shí)現(xiàn)序列號(hào)接口* 剛剛這個(gè)異常是特意留出來(lái)的* 希望印象深刻* instance是001* newInstance002* 他們是不相等* 那目前來(lái)看就違背了單例模式的一個(gè)初衷* 通過(guò)序列化和反序列化拿到了不同的對(duì)象* 而我們只希望拿到同一個(gè)對(duì)象* 那這個(gè)事情要怎么解呢* 那解這個(gè)問(wèn)題也不難* 重要的是理解* 理解他的原理是什么* 我們這里只是以餓漢式來(lái)做例子* 其他方式可以自己嘗試一下* 異曲同工* 那么來(lái)到這個(gè)單例類里面* * * */System.out.println(instance);System.out.println(newInstance);/*** instance和newInstance做一個(gè)對(duì)比* */System.out.println(instance == newInstance);// EnumInstance instance = EnumInstance.getInstance();
// instance.printTest();}
}
public final Object readObject()throws IOException, ClassNotFoundException{if (enableOverride) {return readObjectOverride();}// if nested read, passHandle contains handle of enclosing objectint outerHandle = passHandle;try {Object obj = readObject0(false);handles.markDependency(outerHandle, passHandle);ClassNotFoundException ex = handles.lookupException(passHandle);if (ex != null) {throw ex;}if (depth == 0) {vlist.doCallbacks();}return obj;} finally {passHandle = outerHandle;if (closed && depth == 0) {clear();}}}
private Object readObject0(boolean unshared) throws IOException {boolean oldMode = bin.getBlockDataMode();if (oldMode) {int remain = bin.currentBlockRemaining();if (remain > 0) {throw new OptionalDataException(remain);} else if (defaultDataEnd) {/** Fix for 4360508: stream is currently at the end of a field* value block written via default serialization; since there* is no terminating TC_ENDBLOCKDATA tag, simulate* end-of-custom-data behavior explicitly.*/throw new OptionalDataException(true);}bin.setBlockDataMode(false);}byte tc;while ((tc = bin.peekByte()) == TC_RESET) {bin.readByte();handleReset();}depth++;totalObjectRefs++;try {switch (tc) {case TC_NULL:return readNull();case TC_REFERENCE:return readHandle(unshared);case TC_CLASS:return readClass(unshared);case TC_CLASSDESC:case TC_PROXYCLASSDESC:return readClassDesc(unshared);case TC_STRING:case TC_LONGSTRING:return checkResolve(readString(unshared));case TC_ARRAY:return checkResolve(readArray(unshared));case TC_ENUM:return checkResolve(readEnum(unshared));case TC_OBJECT:return checkResolve(readOrdinaryObject(unshared));case TC_EXCEPTION:IOException ex = readFatalException();throw new WriteAbortedException("writing aborted", ex);case TC_BLOCKDATA:case TC_BLOCKDATALONG:if (oldMode) {bin.setBlockDataMode(true);bin.peek(); // force header readthrow new OptionalDataException(bin.currentBlockRemaining());} else {throw new StreamCorruptedException("unexpected block data");}case TC_ENDBLOCKDATA:if (oldMode) {throw new OptionalDataException(true);} else {throw new StreamCorruptedException("unexpected end of block data");}default:throw new StreamCorruptedException(String.format("invalid type code: %02X", tc));}} finally {depth--;bin.setBlockDataMode(oldMode);}}
private Object readOrdinaryObject(boolean unshared)throws IOException{if (bin.readByte() != TC_OBJECT) {throw new InternalError();}ObjectStreamClass desc = readClassDesc(false);desc.checkDeserialize();Class<?> cl = desc.forClass();if (cl == String.class || cl == Class.class|| cl == ObjectStreamClass.class) {throw new InvalidClassException("invalid class descriptor");}Object obj;try {obj = desc.isInstantiable() ? desc.newInstance() : null;} catch (Exception ex) {throw (IOException) new InvalidClassException(desc.forClass().getName(),"unable to create instance").initCause(ex);}passHandle = handles.assign(unshared ? unsharedMarker : obj);ClassNotFoundException resolveEx = desc.getResolveException();if (resolveEx != null) {handles.markException(passHandle, resolveEx);}if (desc.isExternalizable()) {readExternalData((Externalizable) obj, desc);} else {readSerialData(obj, desc);}handles.finish(passHandle);if (obj != null &&handles.lookupException(passHandle) == null &&desc.hasReadResolveMethod()){Object rep = desc.invokeReadResolve(obj);if (unshared && rep.getClass().isArray()) {rep = cloneArray(rep);}if (rep != obj) {// Filter the replacement objectif (rep != null) {if (rep.getClass().isArray()) {filterCheck(rep.getClass(), Array.getLength(rep));} else {filterCheck(rep.getClass(), -1);}}handles.setObject(passHandle, obj = rep);}}return obj;}
/*** Returns true if represented class is serializable/externalizable and can* be instantiated by the serialization runtime--i.e., if it is* externalizable and defines a public no-arg constructor, or if it is* non-externalizable and its first non-serializable superclass defines an* accessible no-arg constructor. Otherwise, returns false.*/boolean isInstantiable() {requireInitialized();return (cons != null);}
/*** Returns true if represented class is serializable (but not* externalizable) and defines a conformant writeObject method. Otherwise,* returns false.*/boolean hasWriteObjectMethod() {requireInitialized();return (writeObjectMethod != null);}
/*** Invokes the readResolve method of the represented serializable class and* returns the result. Throws UnsupportedOperationException if this class* descriptor is not associated with a class, or if the class is* non-serializable or does not define readResolve.*/Object invokeReadResolve(Object obj)throws IOException, UnsupportedOperationException{requireInitialized();if (readResolveMethod != null) {try {return readResolveMethod.invoke(obj, (Object[]) null);} catch (InvocationTargetException ex) {Throwable th = ex.getTargetException();if (th instanceof ObjectStreamException) {throw (ObjectStreamException) th;} else {throwMiscException(th);throw new InternalError(th); // never reached}} catch (IllegalAccessException ex) {// should not occur, as access checks have been suppressedthrow new InternalError(ex);}} else {throw new UnsupportedOperationException();}}
if (serializable) {AccessController.doPrivileged(new PrivilegedAction<Void>() {public Void run() {if (isEnum) {suid = Long.valueOf(0);fields = NO_FIELDS;return null;}if (cl.isArray()) {fields = NO_FIELDS;return null;}suid = getDeclaredSUID(cl);try {fields = getSerialFields(cl);computeFieldOffsets();} catch (InvalidClassException e) {serializeEx = deserializeEx =new ExceptionInfo(e.classname, e.getMessage());fields = NO_FIELDS;}if (externalizable) {cons = getExternalizableConstructor(cl);} else {cons = getSerializableConstructor(cl);writeObjectMethod = getPrivateMethod(cl, "writeObject",new Class<?>[] { ObjectOutputStream.class },Void.TYPE);readObjectMethod = getPrivateMethod(cl, "readObject",new Class<?>[] { ObjectInputStream.class },Void.TYPE);readObjectNoDataMethod = getPrivateMethod(cl, "readObjectNoData", null, Void.TYPE);hasWriteObjectData = (writeObjectMethod != null);}domains = getProtectionDomains(cons, cl);writeReplaceMethod = getInheritableMethod(cl, "writeReplace", null, Object.class);readResolveMethod = getInheritableMethod(cl, "readResolve", null, Object.class);return null;}});} else {suid = Long.valueOf(0);fields = NO_FIELDS;}
?
總結(jié)
以上是生活随笔為你收集整理的单例设计模式-序列化破坏单例模式原理解析及解决方案的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 单例设计模式-饿汉式
- 下一篇: 单例设计模式-反射攻击解决方案及原理分析