I was doing research on singleton and I have developed a very basic singleton class..
public class SingletonObject {
private static SingletonObject ref;
There are some scenarios where Singleton doesn't behave like.
1.If Singleton Classes destroyed by Garbage Collection, then Reloaded again.
2.More than one Singletons in more than one Virtual Machines
3.More than one Singletons Simultaneously Loaded by Different Class Loaders.
4Copies of Singleton Object that has Undergone Serialization and Deserialization
Via reflection, set ref = null
. By re-assigning it as null
, the logic to lazily construct the singleton will be triggered again on the next invocation of getSingletonObject
.
If you have two classloaders, you'll be able to create a singleton from each classloader.
The document "When is a singleton not a singleton" is also worth a read.
Three ways I can think of are:
If your singleton class is serializable, then you could serialize an instance of it, and deserialize it back and get a second object of that class.
You could avoid this by implementing readResolve method.
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.
}
}
The same class could be loaded by two different class loaders, as such, you could create two instances of your singleton class by simply invoking its getInstance
method in a class loaded by two different class loaders. This approach would work without having to resort to violating the private constructor.
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);
As you have well pointed out, via reflection you could create two instances of the class. I think the previous examples was just a variant of the same approach. But I believe you could prevent these two from happening using a SecurityManager
.
System.setSecurityManager(new SecurityManager());
My answer is:
Why does it matter?
If you are trying to design secure, uncrackable code then a Singleton is not a solution for that. It is designed to force the ordinary developer to use your system instance of it. All of these methods of getting around it require a lot of extra work that someone is not going to do simply to use a different instance of the class.
You can make the singleton constructor public using byte code engineering libraries.
Also, in some older Java versions (this used to work in 1.3), you can simply create a class with the same name, with public constructor and the compile against that class. At runtime this allowed you to create instances of the real class (this loophole has been fixed in the bytecode verification in later JRE versions).