In earlier posts, we discussed how to create the Singleton Design Pattern and what are the different approaches to create Singleton design pattern in Java. As we know that in singleton design pattern we can create only one instance and can access in whole application. But in some cases, it will break the singleton behavior.
There are mainly 3 concepts which can break singleton property of a singleton class. We can discuss how it can break and how to prevent from above concepts as below.
Example to show how reflection can break the singleton pattern:-
Singleton.java,
There are mainly 3 concepts which can break singleton property of a singleton class. We can discuss how it can break and how to prevent from above concepts as below.
- Reflection
Example to show how reflection can break the singleton pattern:-
Singleton.java,
package com.example.demo;
public class Singleton {
private static Singleton instance = null;
private Singleton() {
}
public static Singleton getInstance() {
if (instance == null) {
synchronized (Singleton.class) {
if (instance == null) {
instance = new Singleton();
}
}
}
return instance;
}
}
Using Reflection, we can break the above Singleton principle as shown in the below code.
package com.example.demo;
import java.lang.reflect.Constructor;
public class ReflectionSingleton {
public static void main(String[] args) {
Singleton objOne = Singleton.getInstance();
Singleton objTwo = null;
try {
Constructor constructor = Singleton.class.getDeclaredConstructor();
constructor.setAccessible(true);
objTwo = (Singleton) constructor.newInstance();
} catch (Exception ex) {
System.out.println(ex);
}
System.out.println("Hashcode of Object 1 - "+objOne.hashCode());
System.out.println("Hashcode of Object 2 - "+objTwo.hashCode());
}
}
Output:-
Hashcode of Object 1 - 366712642
Hashcode of Object 2 - 1829164700
Same Singleton instances have different hashcodes so it breaks Singleton Principle.
How to Prevent Singleton pattern from Reflection:-
There are many ways to prevent Singleton pattern from Reflection API, but one of best solution is to throw run time exception in constructor if instance is already exists. In this we can not able to create second instance.
Code:-
private Singleton() throws Exception {
if (instance != null) {
throw new RuntimeException("Instance already exists");
}
}
- Deserialization
Below code is to illustrate how Singleton pattern breaks,
package com.example.demo;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.ObjectInput;
import java.io.ObjectInputStream;
import java.io.ObjectOutput;
import java.io.ObjectOutputStream;
public class DeserializationSingleton {
public static void main(String[] args) throws Exception {
Singleton instanceOne = Singleton.getInstance();
ObjectOutput out = new ObjectOutputStream(new FileOutputStream("file.text"));
out.writeObject(instanceOne);
out.close();
ObjectInput in = new ObjectInputStream(new FileInputStream("file.text"));
Singleton instanceTwo = (Singleton) in.readObject();
in.close();
System.out.println("hashCode of instanceOne is - " + instanceOne.hashCode());
System.out.println("hashCode of instanceTwo is - " + instanceTwo.hashCode());
}
}
Output:-
hashCode of instanceOne is - 1550089733
hashCode of instanceTwo is - 2003749087
As we see above output, there are two objects got created because hashcodes of instanceOne and instanceTwo are different, hence it breaks singleton principle.
Prevent Singleton Pattern from Deserialization:-
To overcome this issue, we need to override readResolve() method in Singleton class and return same Singleton instance.
Singleton.java,
@override
protected Object readResolve() {
return instance;
}
Now run above DeserializationDemo class and see the output,
hashCode of instanceOne is - 1550089733
hashCode of instanceTwo is - 1550089733
- Cloning
Using clone method we can create copy of original object, samething if we applied clone in singleton pattern, it will create two instances one original and another one cloned object. In this case will break Singleton principle as shown in below code.
Implement Cloneable interface and override clone method in the above Singleton class.
Singleton.java
Singleton.java
.....
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
....
Main Class,
package com.example.demo;
public class CloningSingleton {
public static void main(String[] args) throws CloneNotSupportedException, Exception {
Singleton instanceOne = Singleton.getInstance();
Singleton instanceTwo = (Singleton) instanceOne.clone();
System.out.println("hashCode of instance1 - "+instanceOne.hashCode());
System.out.println("hashCode of instance2 - "+instanceTwo.hashCode());
}
}
Output:-
hashCode of instance1 - 366712642
hashCode of instance2 - 1829164700
If we see above output, two instances have different hascodes means these instances are not same.
Prevent Singleton Pattern from Cloning:-
In the above code, breaks the Singleton principle i. e created two instances. To overcome above issue we need to implement/override clone() method and throw an exception i.e CloneNotSupportedException from clone method. If anyone try to create clone object of Singleton, it will throw an exception as see below code.
Singleton.java
......
@Override
protected Object clone() throws CloneNotSupportedException {
throw new CloneNotSupportedException();
}
........
Now you can run the main class, it will throw CloneNotSupportedException while creating clone object of Singleton object.
Thank you for visiting blog...
Related Posts:--
1) Singleton Design Pattern in java with example
2) Factory Design Pattern in Java
3) Builder Design Pattern in Java