序列化破坏单例模式演示
import java.io.Serializable;
public class HungrySingleton implements Serializable{
private final static HungrySingleton hungrySingleton;
static {
hungrySingleton = new HungrySingleton();
}
private HungrySingleton() {}
public static HungrySingleton getInstance() {
return hungrySingleton;
}
}
public class Test {
public static void main(String[] args) throws Exception {
HungrySingleton instance = HungrySingleton.getInstance();
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("singleton_file"));
oos.writeObject(instance);
File file = new File("singleton_file");
ObjectInputStream ois = new ObjectInputStream(new FileInputStream(file));
HungrySingleton newInstance = (HungrySingleton) ois.readObject();
System.out.println(instance);
System.out.println(newInstance);
System.out.println(instance == newInstance);
}
}
输出:
designpattern.creational.singleton.serializable.HungrySingleton@27bc2616
designpattern.creational.singleton.serializable.HungrySingleton@443b7951
false
解决方案
- 添加 readResolve() 方法;
import java.io.Serializable;
public class HungrySingleton implements Serializable{
private final static HungrySingleton hungrySingleton;
static {
hungrySingleton = new HungrySingleton();
}
private HungrySingleton() {}
public static HungrySingleton getInstance() {
return hungrySingleton;
}
private Object readResolve() {
return hungrySingleton;
}
}
public class Test {
public static void main(String[] args) throws Exception {
HungrySingleton instance = HungrySingleton.getInstance();
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("singleton_file"));
oos.writeObject(instance);
File file = new File("singleton_file");
ObjectInputStream ois = new ObjectInputStream(new FileInputStream(file));
HungrySingleton newInstance = (HungrySingleton) ois.readObject();
System.out.println(instance);
System.out.println(newInstance);
System.out.println(instance == newInstance);
}
}
输出:
designpattern.creational.singleton.serializable.HungrySingleton@27bc2616
designpattern.creational.singleton.serializable.HungrySingleton@27bc2616
true
原理解析 & JDK源码跟踪
-
调用ObjectInputStream的readObject()方法,从文件中反序列化出newInstance对象;
-
readObject()方法调用的是readObject0()方法;
-
readObject0()调用readOrdinaryObject(unshared)方法;
4.1 desc是java.io.ObjectStreamClass类对象,是类在序列化时的描述符;
4.2 通过desc判断待反序列化的类是否是可实例化的;
-
通过desc判断待反序列化的类(HungrySingleton)是否有名为readResolve的方法;
-
返回结果说明描述符desc描述的类HungrySingleton是有readResolve()方法的;
-
利用描述符desc进入反射调用的地方;
-
反射调用HungrySingleton的readResolve()方法;
-
HungrySingleton的readResolve()方法被调用;
-
回到main方法中调用的ObjectInputStream的readObject()方法;
-
得到反序列化的结果,就是HungrySingleton中的单例hungrySingleton,而不是新的HungrySingleton实例;