单例模式破解之反射和反序列化
5种单例模式中除了枚举式,其他都存在反射和反序列化的漏洞,下面来讲述一下:
下面是破解代码:
/** * * 描述:测试反射和反序列化破解单例模式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; } }
具体信息,看注释吧