单例模式-反射攻击的解决方案及原理分析

首先我们还是拿饿汉模式作为栗子进行测试,饿汉模式的代码如下:

public class HungrySingleton implements Serializable {

    private static final HungrySingleton instance;

    static {
        instance = new HungrySingleton();
    }
    private HungrySingleton(){
    }

    public static HungrySingleton getInstance(){
        return instance;
    }

    private Object readResolve(){
        return instance;
    }

  1、先写一个利用反射获取实例的方法和直接获取实例的方法,将两者的返回值进行比较,看返回的是否是一个实例。

代码如下:

public class Testreflection {
    public static void main(String[] args) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
        Class object = HungrySingleton.class;
        Constructor constructor = object.getDeclaredConstructor();
        constructor.setAccessible(true);

        HungrySingleton instance = HungrySingleton.getInstance();
        HungrySingleton newInstance = (HungrySingleton) constructor.newInstance();

        System.out.println(instance);
        System.out.println(newInstance);
        System.out.println(instance == newInstance);

     }
    }

  运行后的结果为:可见,两者的结果并不是一个对象,则饿汉模式毅然受到了反射的攻击。

2、那么改如何解决这反射攻击呢?我们知道是在类加载的时候就加载了这个实例的,因为是在类加载的时候就生成了词实例,那么我们可以在构造器里面加一个判断,进行反射防御。代码如下:

测试结果为:

这种方式有一个特点,也就是它对类加载这个时刻就把对象创建好的这种类是ok的,静态内部类的单例也可以用。
对于不是静态类的也需要解决下,要根据创建实例的顺序进行解决。但是无论如何反射都可以访问到类的方法和变量,进行修改,所以非
类加载这个时刻就把对象创建好的这种类,是不能防止反射攻击的。
想要飞得更高,就该忘记地平线!
原文地址:https://www.cnblogs.com/shenwen/p/12676119.html