cracking singleton con otras formas

Estaba investigando sobre singleton y he desarrollado una clase muy básica de singleton.

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 (); } } 

Ahora debajo está la única forma en que he descifrado el singleton …

 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()); } } 

Por favor, indique otras formas en las que el singleton se puede descifrar …

Tres maneras en que puedo pensar son:

Publicación por entregas

Si su clase singleton es serializable, entonces podría serializar una instancia de la misma, deserializarla y obtener un segundo objeto de esa clase.

Puede evitar esto implementando el método 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. } } 

Carga de clase

La misma clase podría ser cargada por dos cargadores de clases diferentes, como tal, podría crear dos instancias de su clase de singleton simplemente invocando su método getInstance en una clase cargada por dos cargadores de clases diferentes. Este enfoque funcionaría sin tener que recurrir a violar el constructor privado .

 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); 

Reflexión

Como bien ha señalado, a través de la reflexión podría crear dos instancias de la clase. Creo que los ejemplos anteriores fueron solo una variante del mismo enfoque. Pero creo que puedes evitar que estos dos ocurran usando un SecurityManager .

 System.setSecurityManager(new SecurityManager()); 

Si tiene dos cargadores de clases, podrá crear un singleton de cada cargador de clases.

También vale la pena leer el documento “Cuando es un singleton no un singleton” .

Mi respuesta es:

¿Por qué eso importa?

Si está tratando de diseñar un código seguro e irrompible, entonces un Singleton no es una solución para eso. Está diseñado para obligar al desarrollador ordinario a usar su instancia de sistema del mismo. Todos estos métodos para sortearlo requieren un montón de trabajo adicional que alguien no va a hacer simplemente para usar una instancia diferente de la clase.

Vía la reflexión, ajuste ref = null . Al reasignarlo como null , la lógica para construir perezosamente el singleton se activará nuevamente en la siguiente invocación de getSingletonObject .

Puede hacer que el constructor singleton sea público utilizando bibliotecas de ingeniería de código de bytes.

Además, en algunas versiones anteriores de Java (esto solía funcionar en 1.3), simplemente puedes crear una clase con el mismo nombre, con el constructor público y comstackr contra esa clase. En tiempo de ejecución, esto le permitió crear instancias de la clase real (esta laguna se ha corregido en la verificación del bytecode en las versiones posteriores de JRE).

Hay algunos escenarios en los que Singleton no se comporta.

1.Si las Clases Singleton fueron destruidas por Garbage Collection, entonces Reloaded nuevamente.
2.Más de un Singleton en más de una Máquina Virtual
3.Más de un Singletons cargado simultáneamente por diferentes cargadores de clases.
4Copias de objeto Singleton que se han sometido a serialización y deserialización