Java设计模式学习-单例模式的漏洞及解决办法

通过对单例模式进行了学习,我们已经对单例模式已经有了一定的认识,但是不知道你们发现没有,也存在几个问题

  • 反射可以破解上一篇博客中的单例模式,其中不包含枚举单例模式。
  • 反序列化也可以破解上一篇中的单例模式,其中也不包含枚举但离开模式。

 

那我们来看下

1), 反射是如何破解单例模式的(下面主要是用懒汉单例模式来做演示)

 

/** 懒汉式 单例模式
 * @author 晓电脑
 *
 */
public class SingletionDemo02 implements Serializable{

    //1 创建静态私有属性
    private static SingletionDemo02 instance;

    //2 创建私有构造器 避免外部直接创建对象
    private SingletionDemo02(){}

    //3 对象提供访问的公共静态方法 访问该属性
    public static synchronized SingletionDemo02 getInstance() throws InterruptedException {
        if (null == instance){
            instance=new SingletionDemo02();
        }
        return instance;
    }

}

 

创建main方法,是用反射进行获取如下

 

/**
 * 通过反射  反序列化来 破解单例模式的解决办法
 */
public class Test03 {
    public static void main (String[] args) {
        try {
            SingletionDemo02 instance1 = SingletionDemo02.getInstance();
            SingletionDemo02 instance2 = SingletionDemo02.getInstance();
            System.out.println(instance1);
            System.out.println(instance2);

            System.out.println("________通过反射方式破解单例模式________");
            Class aClass = Class.forName("com.tuogo.instance.SingletionDemo02");
            //获取默认构造器
            Constructor constructor = aClass.getDeclaredConstructor(null);
            //跳过安全检查
            constructor.setAccessible(true);
            SingletionDemo02 singletionDemo02 = (SingletionDemo02) constructor.newInstance();
            SingletionDemo02 singletionDemo03 = (SingletionDemo02) constructor.newInstance();
            System.out.println(singletionDemo02);
            System.out.println(singletionDemo03);

        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

运行结果为

 

解决办法如下 ,改变懒汉式单例模式的默认构造器 

    private SingletionDemo02(){
        //当 反射通过构造器创建对象的时候判断instance 是否有 如果有直接报错 不让他创建
        if (null != instance){
        throw new RuntimeException();
        }
    }

我们再次运行main 测试

Java设计模式学习-单例模式的漏洞及解决办法_第1张图片

因为当前类实例已经存在,通过方法无法进行创建 , 解决了这个bug问题

 

2), 使用反序列化的方式破解单例模式(这里也使用了懒汉单例模式,代码我就不写了)

需要注意的是,SingletionDemo02 需要实现 Serializable , 如下

Java设计模式学习-单例模式的漏洞及解决办法_第2张图片

main方法来测试 代码如下

 

/**
 * 通过反射  反序列化来 破解单例模式的解决办法
 */
public class Test03 {
    public static void main (String[] args) {
        try {
            SingletionDemo02 instance1 = SingletionDemo02.getInstance();
            SingletionDemo02 instance2 = SingletionDemo02.getInstance();
            System.out.println(instance1);
            System.out.println(instance2);

//            System.out.println("________通过反射方式破解单例模式________");
//            Class aClass = Class.forName("com.tuogo.instance.SingletionDemo02");
//            //获取默认构造器
//            Constructor constructor = aClass.getDeclaredConstructor(null);
//            //跳过安全检查
//            constructor.setAccessible(true);
//            SingletionDemo02 singletionDemo02 = (SingletionDemo02) constructor.newInstance();
//            SingletionDemo02 singletionDemo03 = (SingletionDemo02) constructor.newInstance();
//            System.out.println(singletionDemo02);
//            System.out.println(singletionDemo03);

            System.out.println("______通过反序列化破解单例模式_________");

            //通过反序列化方式破解单例模式
            ObjectOutputStream stream = new ObjectOutputStream(new FileOutputStream("E:/java/tmp/a.txt"));
            stream.writeObject(instance1);
            stream.close();

            ObjectInputStream inputStream = new ObjectInputStream(new FileInputStream("E:/java/tmp/a.txt"));
            SingletionDemo02 singletionDemo021= (SingletionDemo02) inputStream.readObject();
            System.out.println(singletionDemo021);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

 

运行结果为:

 

解决办法如下 在SingletionDemo02 加入ReadResolve()方法

    //方法作用 : 在反序列化的时候 直接调用这个方法返回当前的对象, 而不需要在创建对象
    private Object readResolve() throws ObjectStreamException {
        return instance;
    }

 

再次运行main方法进行测试

 

 

总结: 枚举单例模式--枚举天生保证序列化单例  

 

功能完整、使用简洁、无偿地提供了序列化机制、在面对复杂的序列化或者反射攻击时仍然可以绝对防止多次实例化等优点,单元素的枚举类
型被作者认为是实现Singleton的最佳方法。
                                                                      --《Effective Java 中文版 第二版》

 

你可能感兴趣的:(java设计模式学习,java基础)