通过反射和反序列化可以破解除了枚举之外的单例。
之所以破解不了枚举,是由于枚举的单例时天然的底层的。
所有枚举单例最安全。
1 反射破解
代码1:
package org.yxd.create;
import java.lang.reflect.Constructor;
/*
* 项目名称:DesignMode--设计模式学习
* 包名:org.yxd.create--创建型模式
* 类名:SingletonTest--破解单例,反射
*/
public class SingletonTest2 {
public static void main(String []args) throws Exception{
SingletonDemo6 sd1=SingletonDemo6.getInstance();
SingletonDemo6 sd2=SingletonDemo6.getInstance();
System.out.println("sd1:"+sd1);
System.out.println("sd2:"+sd2);
System.out.println(sd1==sd2);
//反射破解
Class<SingletonDemo6> clazz=(Class<SingletonDemo6>)Class.forName("org.yxd.create.SingletonDemo6");
Constructor<SingletonDemo6> c = clazz.getDeclaredConstructor(null);
c.setAccessible(true);
SingletonDemo6 s3 = c.newInstance();
SingletonDemo6 s4 = c.newInstance();
System.out.println(s3);
System.out.println(s4);
}
}
截图:
2 反序列化破解
代码:
package org.yxd.create;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
/*
* 项目名称:DesignMode--设计模式学习
* 包名:org.yxd.create--创建型模式
* 类名:SingletonTest--破解单例,反序列化
*/
public class SingletonTest3 {
public static void main(String []args) throws Exception{
SingletonDemo6 sd1=SingletonDemo6.getInstance();
SingletonDemo6 sd2=SingletonDemo6.getInstance();
System.out.println("sd1:"+sd1);
System.out.println("sd2:"+sd2);
System.out.println(sd1==sd2);
//反序列化
FileOutputStream fos = new FileOutputStream("d:/a.txt");
ObjectOutputStream oos =new ObjectOutputStream(fos);
oos.writeObject(sd1);
oos.close();
fos.close();
ObjectInputStream ois =new ObjectInputStream(new FileInputStream("d:/a.txt"));
SingletonDemo6 sd3 = (SingletonDemo6) ois.readObject();
System.out.println(sd3);
}
}
截图:
3 防止破解
代码:
package org.yxd.create;
import java.io.ObjectStreamException;
import java.io.Serializable;
/*
* 项目名称:DesignMode--设计模式学习
* 包名:org.yxd.create--创建型模式
* 类名:SingletonDemo2--单例模式之懒汉模式(如何防止反射和反序列化漏洞)
*/
public class SingletonDemo6 implements Serializable{
//类初始化时,不初始化这个对象--延时加载,真正用的时候再创建
private static SingletonDemo6 instance;
private SingletonDemo6(){
//防止反射破解
if(instance!=null){
throw new RuntimeException();
}
}
//方法同步,调用效率低
public static synchronized SingletonDemo6 getInstance(){
if(instance==null){
instance=new SingletonDemo6();
}
return instance;
}
//防止反序列化破解单例,原理:反序列化时,如果定义了readResolve()则直接返回指定的对象。而不需要单独再创建
private Object readResolve() throws ObjectStreamException{
return instance;
}
}