5種單例模式中除了枚舉式,其餘都存在反射和反序列化的漏洞,下面來說述一下:java
下面是破解代碼:cookie
/** * * 描述:測試反射和反序列化破解單例模式Demo06 * @author cookie */ public class Client { public static void main(String[] args) throws Exception { SingletonDemo06 s1 = SingletonDemo06.getInstance(); SingletonDemo06 s2 = SingletonDemo06.getInstance(); System.out.println(s1); System.out.println(s2); //使用反射方式直接調用私有構造器 Class<SingletonDemo06> clazz = (Class<SingletonDemo06>) Class.forName("com.bjsxt.singleton.SingletonDemo06"); Constructor<SingletonDemo06> c = clazz.getDeclaredConstructor(null); c.setAccessible(true);//繞過權限管理,即在true的狀況下,能夠經過構造函數新建對象 SingletonDemo06 s3 = c.newInstance(); SingletonDemo06 s4 = c.newInstance(); System.out.println(s3); System.out.println(s4); //經過反序列化的方式建立多個對象 FileOutputStream fos= new FileOutputStream("d:/a.txt"); ObjectOutputStream oos = new ObjectOutputStream(fos); oos.writeObject(s1); oos.close(); fos.close(); ObjectInputStream ois = new ObjectInputStream(new FileInputStream("d:/a.txt")); SingletonDemo06 s5= (SingletonDemo06) ois.readObject(); System.out.println(s5); } }
而爲了防止反射和反序列化破壞單例模式,須要在單例模式中添加,具體以懶漢式爲例:併發
/** * 單例模式:懶漢模式 測試反射和反序列化破解單例模式 * * @author cookie * */ public class SingletonDemo06 implements java.io.Serializable { // 類加載時,不初始化對象(延時加載:資源利用率高) private static SingletonDemo06 instance; private SingletonDemo06() { if (instance != null) { throw new RuntimeException(); } } // synchronized 防止併發量高的時候,出現多個對象 // 方法同步,調用效率低, public static synchronized SingletonDemo06 getInstance() { if (instance == null) {// 真正用的時候才加載 instance = new SingletonDemo06(); } return instance; } // 在反序列化時,直接調用這個方法,返回指定的對象,無需再新建一個對象 private Object readResolve() { return instance; } }
具體信息,看註釋吧函數