使用反射对单例模式进行攻击的讨论

我们都知道在单例模式中,对构造函数进行私有化private修饰,保证了类不能使用new进行对象的实例化,但是如果使用反射获取构造函数,在进行实例化就会导致private失效。

  1. 作者用中文作为类名,请读者勿怪,纯属喜好,工作中是不允许的哦~~
  2. java初级开发如有错误请多指正。
  3. 在构造函数中对实例是否存在进行判断,抛出异常,用于抵御反射攻击。

1.懒汉模式

public class 懒汉 {

    private static 懒汉 instance = null;

    //private保证无法new出对象
    private 懒汉(){
        if(instance!=null){
            throw  new RuntimeException("不允许多例");
        }
    }

    public static 懒汉 getInstance() throws InterruptedException {
        if(instance==null){
            Thread.sleep(100);
            instance=new 懒汉();
        }
        return instance;
    }

    public static void main(String[] args) throws InterruptedException {


        new Thread(()->{
            懒汉 a = null;
            try {
                a = 懒汉.getInstance();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(a);
        }).start();

        new Thread(()->{
            懒汉 a = null;
            try {
                a = 懒汉.getInstance();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(a);
        }).start();

    }
}

2.饿汉

public class Hungry {
    private static Hungry instance = new Hungry();

    private Hungry(){
        if(instance!=null){
            throw  new RuntimeException("不允许多例");
        }
    }

    public static Hungry getInstance(){
        return instance;
    }

    public static void main(String[] args) {
        //为什么这里可以new 因为这个main还在hungry类中声明
        Hungry instance = new Hungry();
        Hungry instance1 = Hungry.getInstance();
        Hungry instance2 = Hungry.getInstance();
        System.out.println(instance1==instance2);
    }

}

3.静态内部类
也是属于饿汉的一种,类加载时就创建实例

//利用类加载机制,饿汉的一种形式
public class 静态内部类 {

    private 静态内部类(){
        if(InnerClassHolder.instance!=null){
            throw  new RuntimeException("不允许多例");
        }
    }



    static class InnerClassHolder{
        private static 静态内部类 instance = new 静态内部类();
    }

    public static 静态内部类 getInstance(){
        return InnerClassHolder.instance;
    }

    public static void main(String[] args) {
        静态内部类 instance = 静态内部类.getInstance();
        静态内部类 instance2 = 静态内部类.getInstance();
        new Thread(()->{
            静态内部类 b = null;

                b = 静态内部类.getInstance();

            System.out.println(b);
        }).start();
        System.out.println(instance==instance2);
        System.out.println(instance);
    }
}

4.反射攻击


//反射对单例进行创建对象,是否会变成多例
//再次执行私有化构造函数创建对象
public class 反射攻击 {
    public static void main(String[] args) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException, InterruptedException {

        //通过在私有化构造函数中判断抛出异常抵御反射攻击

        //1-------------静态内部类------被反射攻击----异常抵御成功
//        //获取构造函数
//        Constructor<静态内部类> declaredConstructor = 静态内部类.class.getDeclaredConstructor();
//        //构造函数私有化在反射面前不值一提
//        //直接获取使用权
//        declaredConstructor.setAccessible(true);
//        //进行实例化
//        静态内部类 instance = declaredConstructor.newInstance();
//        静态内部类 instance1 = 静态内部类.getInstance();
//        System.out.println(instance1==instance);

        //2-------------懒汉------被反射攻击----异常抵御失败,因为懒汉是用到才创建对象,反射攻击时还不存在对象
//        //获取构造函数
//        Constructor<懒汉> declaredConstructor = 懒汉.class.getDeclaredConstructor();
//        //构造函数私有化在反射面前不值一提
//        //直接获取使用权
//        declaredConstructor.setAccessible(true);
//        //进行实例化
//        懒汉 instance = declaredConstructor.newInstance();
//        懒汉 instance1 = 懒汉.getInstance();
//        System.out.println(instance1==instance);

//        //3-------------饿汉------被反射攻击----异常抵御成功
//        //获取构造函数
//        Constructor<Hungry> declaredConstructor = Hungry.class.getDeclaredConstructor();
//        //构造函数私有化在反射面前不值一提
//        //直接获取使用权
//        declaredConstructor.setAccessible(true);
//        //进行实例化
//        Hungry instance = declaredConstructor.newInstance();
//        Hungry instance1 = Hungry.getInstance();
//        System.out.println(instance1==instance);
    }
}

这里说明一下,只有懒汉模式有被攻击的风险,由于懒汉模式的实例是在第一次使用时才被创建,所以如果最开始就使用反射创建对象会出现多例。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值