如何防止单例模式被JAVA反射攻击
歡迎跳轉(zhuǎn)到本文的原文鏈接:https://honeypps.com/java/how-to-prevent-singleton-from-reflect/
? ? 單例模式相信大家都知道,用過的人不在少數(shù)。之前寫過一篇博文《singleton模式四種線程安全的實現(xiàn)》(參見: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(){} }? ? 但這都是基于一個條件:確保不會通過反射機制調(diào)用私有的構(gòu)造器。
? ? 這里舉個例子,通過JAVA的反射機制來“攻擊”單例模式:
? ?運行結(jié)果:false
? ?可以看到,通過反射獲取構(gòu)造函數(shù),然后調(diào)用setAccessible(true)就可以調(diào)用私有的構(gòu)造函數(shù),所有e1和e2是兩個不同的對象。
? ?如果要抵御這種攻擊,可以修改構(gòu)造器,讓它在被要求創(chuàng)建第二個實例的時候拋出異常。
? ?經(jīng)修改后:
? ? 測試代碼:
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();}} }? ? 運行結(jié)果:
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開始,實現(xiàn)Singleton還有新的寫法,只需編寫一個包含單個元素的枚舉類型。推薦寫法:
? ? 測試代碼:
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();} }? ? 運行結(jié)果:
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)? ? 由此可見這種寫法也可以防止單例模式被“攻擊”。
? ? 而且這種寫法也可以防止序列化破壞單例模式,具體不在舉例了,有關(guān)序列化以及單例模式被序列化破壞可以參考博文《JAVA序列化》(鏈接:http://blog.csdn.net/u013256816/article/details/50474678)。
? ? 單元素的枚舉類型已經(jīng)成為實現(xiàn)Singleton模式的最佳方法。
歡迎跳轉(zhuǎn)到本文的原文鏈接:https://honeypps.com/java/how-to-prevent-singleton-from-reflect/
歡迎支持筆者新作:《深入理解Kafka:核心設(shè)計與實踐原理》和《RabbitMQ實戰(zhàn)指南》,同時歡迎關(guān)注筆者的微信公眾號:朱小廝的博客。總結(jié)
以上是生活随笔為你收集整理的如何防止单例模式被JAVA反射攻击的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 如何用shell脚本编译java工程
- 下一篇: BloomFilter算法概述