http://blog.yohanliyanage.com/2009/09/breaking-the-singleton/
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:
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
package com.test.singleton.securitymgr;
public class Singleton {
private static
final Singleton INSTANCE = new Singleton();
private Singleton()
{
System.out.println("Singleton
Constructor Running...");
}
public static
final Singleton getInstance() {
return
INSTANCE;
}
}
|
Test class:
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
package com.test.singleton.securitymgr;
import java.lang.reflect.Constructor;
public class Test {
public static
void main(String[] args) throws Exception {
Singleton
s = Singleton.getInstance();
Class
clazz = Singleton.class;
Constructor
cons = clazz.getDeclaredConstructor();
cons.setAccessible(true);
Singleton
s2 = (Singleton) cons.newInstance();
}
}
|
Output:
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:
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:
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
|
package com.test.singleton.securitymgr;
import java.lang.reflect.Constructor;
public class Test {
public static
void main(String[] args) throws Exception {
SecurityManager
mgr = new SecurityManager();
System.setSecurityManager(mgr);
Singleton
s = Singleton.getInstance();
Class
clazz = Singleton.class;
Constructor
cons = clazz.getDeclaredConstructor();
cons.setAccessible(true);
Singleton
s2 = (Singleton) cons.newInstance();
}
}
|
Output:
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 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:
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
|
package com.test.singleton.custom;
public class Singleton {
private static
final Singleton INSTANCE = new Singleton();
private Singleton()
{
//
Check if we already have an instance
if
(INSTANCE != null) {
throw new IllegalStateException("Singleton" +
" instance already created.");
}
System.out.println("Singleton
Constructor Running...");
}
public static
final Singleton getInstance() {
return
INSTANCE;
}
}
|
Test class:
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
package com.test.singleton.custom;
import java.lang.reflect.Constructor;
public class Test {
public static
void main(String[] args) throws Exception {
Singleton
s = Singleton.getInstance();
Class
clazz = Singleton.class;
Constructor
cons = clazz.getDeclaredConstructor();
cons.setAccessible(true);
Singleton
s2 = (Singleton) cons.newInstance();
}
}
|
Output:
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 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:
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
|
package com.test.singleton.lazy;
public class LazySingleton {
private static
LazySingleton INSTANCE;
private LazySingleton()
{
}
// If this
method is not synchronized, multiple instances
// can be
created
public static
synchronized LazySingleton getInstance() {
if
(INSTANCE == null) {
//
Lazily instatiate on-demand
INSTANCE
= new LazySingleton();
}
return
INSTANCE;
}
}
|
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.
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
|
package com.test.singleton.serializable;
import java.io.Serializable;
public class Singleton implements Serializable
{
private static
final Singleton INSTANCE = new Singleton();
private Singleton()
{
//
Check if we already have an instance
if
(INSTANCE != null) {
throw new IllegalStateException("Singleton" +
" instance already created.");
}
System.out.println("Singleton
Constructor Running...");
}
public static
final Singleton getInstance() {
return
INSTANCE;
}
// This will
fix the de-serialization issue
private Object
readResolve() {
// Return the available instance instead.
return INSTANCE;
}
}
|
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.
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
|
package com.test.singleton.optimizedlazy;
public class OptimizedLazySingleton {
/**
* Singleton
Instance Wrapper Class.
*
* When this
class is loaded, the singleton instance will be
* created.
Since a class is loaded by a given class loader
* only once,
this will ensure that the Singleton-ness of the
* singleton
will be preserved.
*
*
Additionally, the class will be loaded on the first reference to it,
* which will
occur when the getInstance() method is executed for
* the first
time.
*/
private static
class SingletonInstanceWrapper {
/**
* Singleton Instance.
*/
static
final OptimizedLazySingleton INSTANCE = new OptimizedLazySingleton();
static
{
System.out.println("Instance
Wrapper Class Loaded");
}
}
/**
* Guarded
Constructor.
*/
private OptimizedLazySingleton()
{
//
Check if we already have an instance
if
(SingletonInstanceWrapper.INSTANCE != null) {
throw
new IllegalStateException("Singleton" + " instance already
created.");
}
System.out.println("Singleton
Constructor Running...");
}
/**
* Note that
this method is no longer synchronized !
*/
public static
final OptimizedLazySingleton getInstance() {
System.out.println("Returning
Singleton...");
return
SingletonInstanceWrapper.INSTANCE;
}
}
|