面向對象編程世界裏的單例模式(Singleton)多是設計模式裏最簡單的一種,大多數開發人員都以爲能夠很容易掌握它的用法。單例模式保證一個類僅有一個實例,並提供一個訪問它的全局訪問點。java
然而在某些場景下,這種設計模式的單例特性會被破壞,看下面這個例子:編程
代碼的第三行,這個ABAP類實現了接口if_serializable_object,這意味着它能夠被關鍵字CALL TRANSFORMATION進行序列化和反序列化操做。設計模式
使用下面的ABAP代碼:this
DATA(lo_instance) = zcl_jerry_singleton=>get_instance( ). DATA: s TYPE string. CALL TRANSFORMATION id SOURCE model = lo_instance RESULT XML s. DATA: lo_instance2 TYPE REF TO zcl_jerry_singleton. CALL TRANSFORMATION id SOURCE XML s RESULT model = lo_instance2.
執行以後,在調試器裏發現lo_instance和lo_instance2指向了兩個不一樣的對象實例,說明此時這個ABAP單例模式已經被破壞了。設計
再看看Java,下面是一個最簡單的Java單例模式:3d
然而咱們仍然能夠經過Java的反射機制來破壞這個單例:調試
Class<?> classType = JerrySingleton.class; Constructor<?> c = classType.getDeclaredConstructor(null); c.setAccessible(true); JerrySingleton e1 = (JerrySingleton)c.newInstance(); JerrySingleton e2 = JerrySingleton.getInstance(); System.out.println(e1 == e2);
在Java裏,咱們能夠經過枚舉類來防護這種反射攻擊:code
public enum JerrySingletonAnotherApproach { INSTANCE ; private String name = "Jerry" ; public String getName() { return this.name; } }
這種單例模式的消費代碼:對象
System.out.println("Name:" + JerrySingletonAnotherApproach.INSTANCE.getName());
此時別有用心的攻擊者若是想使用反射機制建立新的實例,會收到下面的報錯信息:blog
Exception in thread "main" java.lang.NoSuchMethodException: singleton.JerrySingletonAnotherApproach.<init>() at java.lang.Class.getConstructor0(Class.java:3082) at java.lang.Class.getDeclaredConstructor(Class.java:2178) at singleton.SingletonAttack.test3(SingletonAttack.java:31) at singleton.SingletonAttack.main(SingletonAttack.java:43)
要獲取更多Jerry的原創文章,請關注公衆號"汪子熙":