public class Singleton { private Singleton(){} private static class SingletonInstance{ private static final Singleton instance = new Singleton(); } public static Singleton getInstance(){ return SingletonInstance.instance; } }我想应该没有不知道这行个类是干嘛的小伙伴了吧,这是单例模式的一种写法。单例模式是每一个 Java boy 必须要掌握的设计模式,它所描述的是在某个进程内,某个类有且仅有一个实例。我们知道要破坏单例模式就必须让它创建多个对象。创建对象的方式无非就几种:
首先单例模式的构造器一定是 private 的,所以 new 这种方式是无法破坏单例模式的。 而 clone 需要实现 Cloneable 接口,单例模式谁如果实现了这个接口,请打死它。所以就剩下反射和反序列化了。本篇文章只讨论反序列化。
public class SerializableSingleton implements Serializable { // 省略部分代码 }然后在对该类进行序列化和反序列化
public class Test { public static void main(String[] args) throws Exception { ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("Singleton.txt")); SerializableSingleton singleton = SerializableSingleton.getInstance(); oos.writeObject(singleton); // 堆代码 duidaima.com ObjectInputStream ois = new ObjectInputStream(new FileInputStream("Singleton.txt")); SerializableSingleton singleton1 = (SerializableSingleton) ois.readObject(); System.out.println("singleton = singleton1:" + (singleton == singleton1)); } }运行结果
singleton = singleton1:false通过对 Singleton 进行反序列化得到了一个全新的对象,这就破坏了 Singleton 的单例性了。我们看 readObject() 源码就知道了。
public final Object readObject() throws IOException, ClassNotFoundException { // 堆代码 duidaima.com int outerHandle = passHandle; try { Object obj = readObject0(false); //... return obj; } finally { //... } }调用 readObject0() :
private Object readObject0(boolean unshared) throws IOException { // ... try { switch (tc) { // ... case TC_OBJECT: // readObject0() return checkResolve(readOrdinaryObject(unshared)); // ... } } finally { depth--; bin.setBlockDataMode(oldMode); } }readObject0() 是根据反序列化对象的不同执行不同的方法来反序列化一个实例对象。我们这里是 Object,所以进一步看 readOrdinaryObject()。
private Object readOrdinaryObject(boolean unshared) throws IOException { // ... 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); } // ... 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 object if (rep != null) { if (rep.getClass().isArray()) { filterCheck(rep.getClass(), Array.getLength(rep)); } else { filterCheck(rep.getClass(), -1); } } handles.setObject(passHandle, obj = rep); } } return obj; }这段代码最核心的地方就是:
obj = desc.isInstantiable() ? desc.newInstance() : null;底层依然是利用反射的方式来创建一个新对象。
if (obj != null && handles.lookupException(passHandle) == null && desc.hasReadResolveMethod()) { //.... }判断反序列化的类是否已实现了 readResolve() ,如果有则会调用该方法,我们只需要在该方法里面返回原对象就可以了。验证下。
public class SerializableSingleton implements Serializable { // ... private Object readResolve() { return SingletonInstance.instance; } }执行结果:
singleton = singleton1:true执行结果为 true,就说明序列化和反序列化出来的是同一个对象。所以,要想防止单例被反序列化破坏,就让单例实现 readResolve()方法,返回同一个对象即可。