欢迎支持笔者新作:《深入理解Kafka:核心设计与实践原理》和《RabbitMQ实战指南》,同时欢迎关注笔者的微信公众号:朱小厮的博客。

欢迎跳转到本文的原文链接:https://honeypps.com/java/how-to-prevent-singleton-from-reflect/

单例模式相信大家都知道,用过的人不在少数。之前写过一篇博文《singleton模式四种线程安全的实现》(参见:http://blog.csdn.net/u013256816/article/details/50427061),讲诉了单例模式的四种写法,并指出占位符模式的写法比较ok,详见如下:

package com.effective.singleton;public class Elvis
{private static boolean flag = false;private Elvis(){}private  static class SingletonHolder{private static final Elvis INSTANCE = new Elvis();}public static Elvis getInstance(){return SingletonHolder.INSTANCE;}public void doSomethingElse(){}
}

但这都是基于一个条件:确保不会通过反射机制调用私有的构造器。
    这里举个例子,通过JAVA的反射机制来“攻击”单例模式:

package com.effective.singleton;import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;public class ElvisReflectAttack
{public static void main(String[] args) throws InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException, NoSuchMethodException, SecurityException{Class<?> classType = Elvis.class;Constructor<?> c = classType.getDeclaredConstructor(null);c.setAccessible(true);Elvis e1 = (Elvis)c.newInstance();Elvis e2 = Elvis.getInstance();System.out.println(e1==e2);}}

运行结果:false
   可以看到,通过反射获取构造函数,然后调用setAccessible(true)就可以调用私有的构造函数,所有e1和e2是两个不同的对象。
   如果要抵御这种攻击,可以修改构造器,让它在被要求创建第二个实例的时候抛出异常。
   经修改后:

package com.effective.singleton;public class ElvisModified
{private static boolean flag = false;private ElvisModified(){synchronized(ElvisModified.class){if(flag == false){flag = !flag;}else{throw new RuntimeException("单例模式被侵犯!");}}}private  static class SingletonHolder{private static final ElvisModified INSTANCE = new ElvisModified();}public static ElvisModified getInstance(){return SingletonHolder.INSTANCE;}public void doSomethingElse(){}
}

测试代码:

package com.effective.singleton;import java.lang.reflect.Constructor;public class ElvisModifiedReflectAttack
{public static void main(String[] args){try{Class<ElvisModified> classType = ElvisModified.class;Constructor<ElvisModified> c = classType.getDeclaredConstructor(null);c.setAccessible(true);ElvisModified e1 = (ElvisModified)c.newInstance();ElvisModified e2 = ElvisModified.getInstance();System.out.println(e1==e2);}catch (Exception e){e.printStackTrace();}}
}

运行结果:

Exception in thread "main" java.lang.ExceptionInInitializerErrorat com.effective.singleton.ElvisModified.getInstance(ElvisModified.java:27)at com.effective.singleton.ElvisModifiedReflectAttack.main(ElvisModifiedReflectAttack.java:17)
Caused by: java.lang.RuntimeException: 单例模式被侵犯!at com.effective.singleton.ElvisModified.<init>(ElvisModified.java:16)at com.effective.singleton.ElvisModified.<init>(ElvisModified.java:7)at com.effective.singleton.ElvisModified$SingletonHolder.<clinit>(ElvisModified.java:22)... 2 more

可以看到,成功的阻止了单例模式被破坏。
    从JDK1.5开始,实现Singleton还有新的写法,只需编写一个包含单个元素的枚举类型。推荐写法:

package com.effective.singleton;public enum SingletonClass
{INSTANCE;public void test(){System.out.println("The Test!");}
}

测试代码:

package com.effective;import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;import com.effective.singleton.SingletonClass;public class TestMain
{public static void main(String[] args) throws NoSuchMethodException, SecurityException, InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException{Class<SingletonClass> classType = SingletonClass.class;Constructor<SingletonClass> c = (Constructor<SingletonClass>) classType.getDeclaredConstructor();c.setAccessible(true);c.newInstance();}
}

运行结果:

Exception in thread "main" java.lang.NoSuchMethodException: com.effective.singleton.SingletonClass.<init>()at java.lang.Class.getConstructor0(Unknown Source)at java.lang.Class.getDeclaredConstructor(Unknown Source)at com.effective.TestMain.main(TestMain.java:22)

由此可见这种写法也可以防止单例模式被“攻击”。
    而且这种写法也可以防止序列化破坏单例模式,具体不在举例了,有关序列化以及单例模式被序列化破坏可以参考博文《JAVA序列化》(链接:http://blog.csdn.net/u013256816/article/details/50474678)。
    单元素的枚举类型已经成为实现Singleton模式的最佳方法。

欢迎跳转到本文的原文链接:https://honeypps.com/java/how-to-prevent-singleton-from-reflect/

欢迎支持笔者新作:《深入理解Kafka:核心设计与实践原理》和《RabbitMQ实战指南》,同时欢迎关注笔者的微信公众号:朱小厮的博客。

如何防止单例模式被JAVA反射攻击相关推荐

  1. java 防止反射_如何防止JAVA反射对单例类的攻击?

    在我的上篇随笔中,我们知道了创建单例类有以下几种方式: (1).饿汉式; (2).懒汉式(.加同步锁的懒汉式.加双重校验锁的懒汉式.防止指令重排优化的懒汉式); (3).登记式单例模式; (4).静态 ...

  2. Java设计模式——为什么要用枚举实现单例模式(避免反射、序列化问题)

    1.序言   相信如果能看到我这篇博客的小伙伴,肯定都看过Joshua Bloch大神说过的这句话:"单元素的枚举类型已经成为实现Singleton的最佳方法".其实,第一次读到这 ...

  3. java 防止反射_Java设计模式(一):单例模式,防止反射和反序列化漏洞

    一.懒汉式单例模式,解决反射和反序列化漏洞 package com.iter.devbox.singleton; import java.io.ObjectStreamException; impor ...

  4. java 反射 单列_轻松掌握Java单例模式

    单例模式是23中设计模式中最简单的设计模式,在企业开发中也应用的特别多.单例模式的优点是:项目中有且仅有一个实例. 特点:构造器私有化,对象私有化,只提供一个对外访问的接口. 应用场景: 1.系统需要 ...

  5. 单例设计模式-反射攻击解决方案及原理分析

    package com.learn.design.pattern.creational.singleton;import java.io.Serializable;public class Hungr ...

  6. 为什么要用枚举实现单例模式(避免反射、序列化问题)

    1 引言 ​ 相信如果能看到我这篇博客的小伙伴,肯定都看过Joshua Bloch大神说过的这句话:"单元素的枚举类型已经成为实现Singleton的最佳方法".其实,第一次读到这 ...

  7. Java 反射?反射有什么缺点?你是怎么理解反射的(为什么框架需要反射)?

    ava Java 基础这部分一些简单的问题就直接没有放上来. 需要资料的朋友麻烦一键三连之后点此免费获取! 基础: Java 反射?反射有什么缺点?你是怎么理解反射的(为什么框架需要反射)? 谈谈对 ...

  8. Java反射设计模式

    Java反射&设计模式 反射机制 什么是Java反射 反射机制的作用 反射机制的应用场景 反射机制获取类的三种方法 反射创建对象的方式 反射创建api 使用反射为类私有属性赋值 JDBC反射加 ...

  9. java 反射详解通俗易懂

    Java的反射机制是Java特性之一,反射机制是构建框架技术的基础所在.灵活掌握Java反射机制,对大家以后学习框架技术有很大的帮助. 那么什么是Java的反射呢? 大家都知道,要让Java程序能够运 ...

最新文章

  1. (组合)Binomial Showdown
  2. 小学生学python到底能干什么-小学生都学Python了,你还没用万矿?
  3. LeetCode-剑指 Offer 50. 第一个只出现一次的字符
  4. Python中有几种办法交换两个变量的值?
  5. request 和require区别_JAVA WEB开发中涉及到的get和post请求,他们的区别
  6. 获取listview当前滚动的高度
  7. 机器学习笔记(《统计学习方法》李航and《机器学习》周志华)
  8. Linux配置本地/外网访问Apache服务器,手把手教你搭建Ngrok——以小米球Ngrok为例
  9. 服务器c盘logs文件夹,c盘的logs文件夹有什么用
  10. android使用Itext库生成PDF文件
  11. 计算机绘图说课视频,机械图识读与计算机绘图说课PPT课件.ppt
  12. 如何禁用电脑文件共享
  13. 读书寄语:有一种感动叫守口如瓶
  14. linux quota原理,[转载]linux下quota实现
  15. 家装灯线走线图_家装吊顶筒灯电线走法设计图 4款客厅天花吊顶龙骨筒灯顶线布置图...
  16. jQuery中的动画 -- 案例
  17. Illegal unquoted character ((CTRL-CHAR, code 10)): has to be escaped using backslash to be included
  18. exit() _exit()
  19. OpenAI 首个研究成果 生成式模型系列
  20. 苹果公司的企业文化_【全景标杆】乔布斯给苹果留下了什么样的企业文化?

热门文章

  1. 用python画一个人_用turtle画个单身狗送给自己~
  2. basequickadapter详解_BaseRecyclerViewAdapter(持续更新!)
  3. 在js中如何判断一个对象是否为空
  4. MobX - 基于响应式的状态管理
  5. java 判断是否大于指定版本号
  6. 看苏宁易购的运营保障体系如何hold住818大促
  7. hexo在git上搭建个人博客
  8. Xamarin Live Player Preview 2: 连续运行和调试应用程序
  9. redis安装全过程
  10. 记crontab脚本未执行问题排查