Breaking the Singleton
One of my colleagues at work raised a question regarding ‘breaking the singleton’ using Java Reflection, and asked of a way to avoid such actions. It inspired me, and started to think about a way to avoid it, and following is the outcome of it.
A word of caution before continuing any further. I do not recommend at all that any of the following methods (except for SecurityManagers) shall be used in your code to restrict reflective access to your singletons. Such access is possible in Java because there is a good reason. Sometimes, when you are working with old code (may be even not so old code), you might need to be able to reflectively access the singleton, and you might not be able to predict that at the time of writing your code.
Singleton pattern can be broken using reflection, as shown below.
Singleton class:
Test class:
Output:
Java’s own way of handling such mischievous behavior is to use a SecurityManager which restricts the ‘supressAccessChecks’permission of java.lang.reflect.ReflectPermission. The default security manager implementation does it. Following example shows this:
Singleton Constructor Running...
Singleton Constructor Running...
Java’s own way of handling such mischievous behavior is to use a SecurityManager which restricts the ‘supressAccessChecks’permission of java.lang.reflect.ReflectPermission. The default security manager implementation does it. Following example shows this:
Test class:
Output:
But the downside of this is that some of the libraries that we use, for example ‘Hibernate’ relies on reflective access to object properties. When we mark a field (instead of public getter / setter) with @Id or @Column annotation, Hibernate uses reflection to access the particular field to obtain the meta-data. So if we put a security manager which restricts reflective access, theoretically Hibernate should fail (I haven’t tried this myself). There might be workarounds for this (may be annotating getters setters instead of field would fix this).
On the other hand, thinking about the problem, I thought of another solution, which seems to solve this. I didn’t put my mind into breaking this, so I’m not sure if this could be broken.
In this approach, the constructor checks to see if the instance variable is already set. If it is, then the constructor would throw an exception avoiding the instantiation.
Singleton Constructor Running...
Exception in thread "main" java.security.AccessControlException: access denied (java.lang.reflect.ReflectPermission suppressAccessChecks)
at java.security.AccessControlContext.checkPermission(AccessControlContext.java:323)
at java.security.AccessController.checkPermission(AccessController.java:546)
at java.lang.SecurityManager.checkPermission(SecurityManager.java:532)
at java.lang.reflect.AccessibleObject.setAccessible(AccessibleObject.java:107)
at com.test.singleton.securitymgr.Test.main(Test.java:17)
But the downside of this is that some of the libraries that we use, for example ‘Hibernate’ relies on reflective access to object properties. When we mark a field (instead of public getter / setter) with @Id or @Column annotation, Hibernate uses reflection to access the particular field to obtain the meta-data. So if we put a security manager which restricts reflective access, theoretically Hibernate should fail (I haven’t tried this myself). There might be workarounds for this (may be annotating getters setters instead of field would fix this).
On the other hand, thinking about the problem, I thought of another solution, which seems to solve this. I didn’t put my mind into breaking this, so I’m not sure if this could be broken.
In this approach, the constructor checks to see if the instance variable is already set. If it is, then the constructor would throw an exception avoiding the instantiation.
Singleton class:
Test class:
Output:
Apart from above, another case is when using lazily instantiated singletons as below, if the method which does the instantiation is not thread-safe, multiple instances could be created.
Singleton Constructor Running...
Exception in thread "main" java.lang.reflect.InvocationTargetException
at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:39)
at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:27)
at java.lang.reflect.Constructor.newInstance(Constructor.java:513)
at com.test.singleton.custom.Test.main(Test.java:15)
Caused by: java.lang.IllegalStateException: Singleton instance already created.
at com.test.singleton.custom.Singleton.(Singleton.java:12)
... 5 more
Apart from above, another case is when using lazily instantiated singletons as below, if the method which does the instantiation is not thread-safe, multiple instances could be created.
Singleton class:
On the other hand, there’s another way to break the singleton pattern, which cannot be solved using either of above, and any way that I could think of. That is to use multiple class loaders. When the same class is loaded by two different class loaders, that same class is treated as if they are two different classes. That is because the Java identifies unique classes not only using it’s fully qualified name, but also with the class loader which loaded the class. If our singleton above is loaded by two class loaders, there will be two instances of it.
That being said, use of Singletons should be done with care, especially when the singleton maintains state. In distributed environments such as clusters (each VM will have its own singleton instance), relying on the “singleton-ness”of singletons could lead to hard to find bugs.
Update : Serializable Singletons (25-Sep-2009)
Another scenario where Singleton pattern could probably break is when using serialization. If the Singleton class is serializable, performing a deserialization could yield multiple instances. The solution provided above with a check in the constructor would not be able to resolve this, as constructors are not invoked at deserialization. However, it is possible to overcome this by implementing special methods provided by Java Serialization API such as writeReplace() / readResolve().
Following example demonstrates this. Thanks to Gireesh Kumar for bringing this up for discussion.
Update : Improved Lazy Singleton (29-Sep-2009)
A reader (StarWars) has shown the lazy singleton implementation can be improved with the use of a static inner class for initializing the singleton. This would remove the necessity of synchronizing the getInstance() method, which would remove the synchronization overhead. Thanks to StarWars for suggesting this.
Additionally, this approach will also allow us to overcome the reflection vulnerability of Lazy Singleton.
The following code outlines the structure of the optimized version of Lazy Singleton.
No comments:
Post a Comment