zoukankan      html  css  js  c++  java
  • 反射如何破坏单例模式

    一个单例类:

    
    
    public class Singleton {
        private static Singleton instance = new Singleton();   
    
        private Singleton() {} 
    
        public static Singleton getInstance() {
            return instance;
        }
    }
     

    通过反射破坏单例模式:

    
    
    public class Test {
        public static void main(String[] args) throws Exception{
            Singleton s1 = Singleton.getInstance();
    
            Constructor<Singleton> constructor = Singleton.class.getDeclaredConstructor();
            constructor.setAccessible(true);
            Singleton s2 = constructor.newInstance();
    
            System.out.println(s1.hashCode());
            System.out.println(s2.hashCode());
    
        }
    }
    
    
    

      

    输出结果:
    671631440

    935563443

    结果表明s1和s2是两个不同的实例了。

    通过反射获得单例类的构造函数,由于该构造函数是private的,通过setAccessible(true)指示反射的对象在使用时应该取消 Java 语言访问检查,使得私有的构造函数能够被访问,这样使得单例模式失效。

     

    如果要抵御这种攻击,要防止构造函数被成功调用两次。需要在构造函数中对实例化次数进行统计,大于一次就抛出异常。

    
    
    public class Singleton {
        private static int count = 0;
    
        private static Singleton instance = null; 
    
        private Singleton(){
            synchronized (Singleton.class) {
                if(count > 0){
                    throw new RuntimeException("创建了两个实例");
                }
                count++;
            }
    
        }
    
        public static Singleton getInstance() {
            if(instance == null) {
                instance = new Singleton();
            }
            return instance;
        }
    
        public static void main(String[] args) throws Exception {
    
            Constructor<Singleton> constructor = Singleton.class.getDeclaredConstructor();
            constructor.setAccessible(true);
            Singleton s1 = constructor.newInstance();
            Singleton s2 = constructor.newInstance();
        }
    
    }
    
    执行结果:
    Exception in thread "main" java.lang.reflect.InvocationTargetException
        at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
        at sun.reflect.NativeConstructorAccessorImpl.newInstance(Unknown Source)
        at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(Unknown Source)
        at java.lang.reflect.Constructor.newInstance(Unknown Source)
        at com.yzz.reflect.Singleton.main(Singleton.java:33)
    Caused by: java.lang.RuntimeException: 创建了两个实例
        at com.yzz.reflect.Singleton.<init>(Singleton.java:14)
        ... 5 more
    
    
    
    在通过反射创建第二个实例时抛出异常,防止实例化多个对象。构造函数中的synchronized是为了防止多线程情况下实例化多个对象。
  • 相关阅读:
    jenkins集成 Maven 构建工具
    CentOS 7.x 安装 Maven
    jenkins构建容器
    Jenkins常用插件
    jenkins插件加速
    抓包工具的前端性能测试技巧(fiddler)
    request中的POST类型及展示
    jmeter参数化处理json数据的注意事项
    jenkins+ant+jmeter在Linux下配置时的注意点
    jmeter中脚本数据分离并生成报告
  • 原文地址:https://www.cnblogs.com/wyb628/p/6371827.html
Copyright © 2011-2022 走看看