单例设计模式-序列化破坏单例模式?反射攻击?
1、问题猜想,假如将一个对象通过序列化放到一个文件后,再取出来看是否与本身相等?
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 IOException, ClassNotFoundException { HungrySingleton instance = HungrySingleton.getInstance(); ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("single_file")); oos.writeObject(instance); File file = new File("single_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); } }
结果:
com.wenwen.design.pattern.Creational.singleton.HungrySingleton@45ee12a7 com.wenwen.design.pattern.Creational.singleton.HungrySingleton@7699a589 false
由此可见,instance和newInstance不相等,就违背了单例模式的一个初衷,通过序列化和反序列化拿到了不同的对象。而我们是希望拿到一个对象。
SRE实战 互联网时代守护先锋,助力企业售后服务体系运筹帷幄!一键直达领取阿里云限量特价优惠。那么如何解决呢?
在单例中加一个方法就可解决,如下代码所示:
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; } }
再次运行测试类之后,结果如下:
com.wenwen.design.pattern.Creational.singleton.HungrySingleton@45ee12a7 com.wenwen.design.pattern.Creational.singleton.HungrySingleton@45ee12a7 true
为什么如此神奇呢?这就要大家深入看下源码了。
2、单例模式是否存在反射攻击?
public static void main(String[] args) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException { Class objectClass = HungrySingleton.class; Constructor constructor = objectClass.getDeclaredConstructor(); constructor.setAccessible(true); HungrySingleton hungrySingleton = HungrySingleton.getInstance(); HungrySingleton newInstance = (HungrySingleton) constructor.newInstance(); System.out.println(hungrySingleton); System.out.println(newInstance); }
当出现.setAccessible(true);作用就是让我们在用反射时访问私有变量,那么我们的单例就会受到反射攻击的危害。结果不会报错。
com.wenwen.design.pattern.Creational.singleton.HungrySingleton@677327b6
com.wenwen.design.pattern.Creational.singleton.HungrySingleton@14ae5a5

更多精彩