用其他方式破解单身人士

我正在研究单身人士,我开发了一个非常基本的单身人士课程。

public class SingletonObject { private static SingletonObject ref; private SingletonObject () //private constructor { } public static synchronized SingletonObject getSingletonObject() { if (ref == null) ref = new SingletonObject(); return ref; } public Object clone() throws CloneNotSupportedException {throw new CloneNotSupportedException (); } } 

现在下面是我破解单身人士的一种方式..

 public class CrackingSingleton { public static void main(String[] args) throws ClassNotFoundException, IllegalArgumentException, SecurityException, InstantiationException, IllegalAccessException, InvocationTargetException { //First statement retrieves the Constructor object for private constructor of SimpleSingleton class. Constructor pvtConstructor = Class.forName("CrackingSingleton.SingletonObject").getDeclaredConstructors()[0]; //Since the constructor retrieved is a private one, we need to set its accessibility to true. pvtConstructor.setAccessible(true); //Last statement invokes the private constructor and create a new instance of SimpleSingleton class. SingletonObject notSingleton1 = ( SingletonObject) pvtConstructor.newInstance(null); System.out.println(notSingleton1.hashCode()); System.out.println("notSingleton1 --->"+notSingleton1.toString()); SingletonObject notSingleton2 = ( SingletonObject) pvtConstructor.newInstance(null); System.out.println("notSingleton2 --->"+notSingleton2.hashCode()); System.out.println(notSingleton2.toString()); } } 

请告知其他单身人士可能破裂的方式.. !!

我能想到的三种方式是:

序列化

如果你的单例类是可序列化的,那么你可以序列化它的一个实例,然后反序列化它并获得该类的第二个对象。

您可以通过实现readResolve方法来避免这种情况。

 public class Singleton implements Serializable { private static final Singleton INSTANCE = new Singleton(); public static Singleton getInstance(){ return INSTANCE; } public Object readResolve() throws ObjectStreamException { return INSTANCE; //ensure singleton is returned upon deserialization. } } 

class级加载

同一个类可以由两个不同的类加载器加载,因此,您可以通过在由两个不同的类加载器加载的类中调用其getInstance方法来创建单个类的两个实例。 这种方法可以工作, 而不必诉诸于违反私人构造函数

 ClassLoader cl1 = new URLClassLoader(new URL[]{"singleton.jar"}, null); ClassLoader cl2 = new URLClassLoader(new URL[]{"singleton.jar"}, null); Class singClass1 = cl1.loadClass("hacking.Singleton"); Class singClass2 = cl2.loadClass("hacking.Singleton"); //... Method getInstance1 = singClass1.getDeclaredMethod("getInstance", ...); Method getInstance2 = singClass2.getDeclaredMethod("getInstance", ...); //... Object singleton1 = getInstance1.invoke(null); Object singleton2 = getInstance2.invoke(null); 

reflection

正如您已经指出的那样,通过reflection,您可以创建该类的两个实例。 我认为前面的例子只是同一种方法的一种变体。 但我相信你可以使用SecurityManager防止这两者发生。

 System.setSecurityManager(new SecurityManager()); 

如果你有两个类加载器,你将能够从每个类加载器创建一个单例。

文件“何时是单身人士不是单身人士”也值得一读。

我的回答是:

为什么这有关系?

如果您正在尝试设计安全,不可破解的代码,那么Singleton就不是解决方案。 它旨在强制普通开发人员使用它的系统实例。 所有这些绕过它的方法都需要大量额外的工作,而有些人不会仅仅使用不同的类实例。

通过reflection,设置ref = null 。 通过将其重新赋值为null ,将在下一次调用getSingletonObject再次触发延迟构造单例的逻辑。

您可以使用字节代码工程库将单例构造函数公开。

此外,在一些较旧的Java版本中(这曾经在1.3中工作),您可以简单地创建一个具有相同名称的类,使用公共构造函数和针对该类的编译。 在运行时,这允许您创建真实类的实例(此漏洞已在以后的JRE版本中的字节码validation中得到修复)。

在某些情况下,Singleton的行为不像。

1.如果单例类被垃圾收集破坏,则重新加载。
2.多个虚拟机中不止一个单身人士
3.不同类型装载机同时装载的单个单人。
具有经过序列化和反序列化的Singleton对象的4Copies