反射破坏单例模式以及怎样防御

先贴几个比较全的java反射博客
Java反射:用最直接的大白话来聊一聊Java中的反射机制Java基础之—反射(非常重要)Java反射技术详解
前面介绍的单例模式的实现方式: 设计模式之单例模式
单例模式的设计在于只保留一个公有静态函数来获取唯一的实例 , 其他方法(构造函数)或字段为私有 , 外界不能访问 。
而java反射则突破了构造函数私有的限制 , 可以获取单例类的私有构造函数并使用 。
//得到该类在内存中的字节码对象Class objectClass = Class.forName("com.xt.designmode.creational.singleton.hungryBoyClass.Singleton");//获取构造器Constructor constructor = objectClass.getDeclaredConstructor();//暴力反射 , 解除私有限定constructor.setAccessible(true);Singleton reflectInstance = (Singleton) constructor.newInstance();
我们针对所有实现单例模式的方法使用如下测试
public class ReflectTest {public static void main(String[] args) throws InvocationTargetException, InstantiationException, IllegalAccessException, NoSuchMethodException, ClassNotFoundException {Class objectClass = Class.forName("com.xt.designmode.creational.singleton.hungryBoyClass.Singleton");Constructor constructor = objectClass.getDeclaredConstructor();constructor.setAccessible(true);Singleton instance = Singleton.getInstance();Singleton reflectInstance = (Singleton) constructor.newInstance();System.out.println(instance);System.out.println(reflectInstance);//对象类型 ,  == 比较的是地址if(instance != reflectInstance){System.out.printf("创建了两个实例\n");}else{System.out.printf("只创建了一个实例\n");}}}
除开枚举式实现的单例模式 , 其余的方式都可以被反射直接获取到私有的构造器来创建新实例 。
我们先看看枚举类是怎样防御反射攻击的 。
像我 设计模式之单例模式这篇博客实现的枚举类实现单例是不能抵抗反射攻击的 , 因为我们不反射枚举类 , 直接反射类就可以了 , 并且因为类的构造函数是的 , 所以真想攻击的话 , 直接去new 实例就好了 。(逃
public enum Singleton {INSTANCE;private Resource resource;private Singleton(){resource = new Resource();}public Resource getInstance(){return resource;}}
我们采用如下形式enum 枚举类实现单例模式
public enum EnumSingleton {INSTANCE;private EnumSingleton(){}public static EnumSingleton getInstance() {return INSTANCE;}}
测试
public class ReflectTest {public static void main(String[] args) throws InvocationTargetException, InstantiationException, IllegalAccessException, NoSuchMethodException, ClassNotFoundException {Class objectClass = Class.forName("com.xt.designmode.creational.singleton.destroy.EnumSingleton");Constructor constructor = objectClass.getDeclaredConstructor();constructor.setAccessible(true);//枚举类式的单例模式EnumSingleton instance = EnumSingleton.INSTANCE;EnumSingleton reflectInstance = (EnumSingleton) constructor.newInstance();if(instance != reflectInstance){System.out.printf("创建了两个实例\n");}else{System.out.printf("只创建了一个实例\n");}}}
会报出找不到无参的构造方法的异常 。这个问题多个博主也遇到过 , 通过反编译的方式找到了问题所在 。
我们使用javac来对代码进行编译,使用jad工具对class代码进行反编译
javac工具读由java语言编写的类和接口的定义 , 并将它们编译成字节代码的class文件