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


运用cmd终端或者IDEA终端 cd 到要编译文件的所在文件夹下面 , 运行以下命令将.java编译成.class文件
javac EnumSingleton.java

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

文章插图
然后使用jad 工具来对class文件进行反编译
jad下载地址
我这里下载的是版本 , 然后放到一个文件夹下面 , 最后将文件夹位置设置到系统的环境变量 。如下所示 , 是我的jad.exe所在的文件夹路径
将.class文件复制到一个指定的文件夹下面 , 不然在源代码文件夹下 , 使用jad反编译生成的.java文件会覆盖原来的文件
jad -sjava EnumSingleton.class
生成的反编译代码如下所示:
// Decompiled by Jad v1.5.8g. Copyright 2001 Pavel Kouznetsov.// Jad home page: http://www.kpdus.com/jad.html// Decompiler options: packimports(3) // Source File Name:EnumSingleton.javapackage com.xt.designmode.creational.singleton.destroy;public final class EnumSingleton extends Enum{public static EnumSingleton[] values(){return (EnumSingleton[])$VALUES.clone();}public static EnumSingleton valueOf(String s){return (EnumSingleton)Enum.valueOf(com/xt/designmode/creational/singleton/destroy/EnumSingleton, s);}private EnumSingleton(String s, int i){super(s, i);}public static EnumSingleton getInstance(){return INSTANCE;}public static final EnumSingleton INSTANCE;private static final EnumSingleton $VALUES[];static {INSTANCE = new EnumSingleton("INSTANCE", 0);$VALUES = (new EnumSingleton[] {INSTANCE});}}
会发现枚举类内部其实是一个有参的构造函数 。
也可以通过反射获取所有的构造方法 , 打印出来看一看 , 瞧一瞧
Constructor[] cons=objectClass.getDeclaredConstructors();for(Constructorcon:cons) {System.out.println("构造方法:"+con);}
如下所示 , 和上面反编译的代码一样 。只有个和int参数的有参构造器
所以我们获取其带有和int参数的有参构造
Constructor constructor = objectClass.getDeclaredConstructor(String.class,int.class);
然后再通过这个构造器new一个实例
抛出异常 , 不能通过反射创建枚举类对象
debug进去看是那个地方抛出的异常 , 可以看见在反射的()方法里面 , 会检查该类是否ENUM修饰 , 如果是则抛出异常 , 反射失败
有如下方法 , 对于枚举类来说 , 通过反射创建枚举类实例的路是堵死了 , 所以枚举类实现单例模式不用怕反射破坏 。
public T newInstance(Object ... initargs)throws InstantiationException, IllegalAccessException,IllegalArgumentException, InvocationTargetException{//其他代码已删除if ((clazz.getModifiers() & Modifier.ENUM) != 0)throw new IllegalArgumentException("Cannot reflectively create enum objects");//其他代码已删除}
那么其他单例模式的实现方式可以怎么防御反射攻击呢?
反射破坏单例模式以及怎样防御

文章插图
既然反射是通过暴力获取单例类的私有构造器来构造新实例 , 那就从构造器入手
饿汉式
【反射破坏单例模式以及怎样防御】private Singleton(){if(singleton!=null){throw new RuntimeException("单例模式下 , 禁止使用反射创建新实例");}}