java单例-通过反射防止多次创建
我有一个这样的单身汉java单例-通过反射防止多次创建,java,singleton,Java,Singleton,我有一个这样的单身汉 public class BookingFactory { private final static BookingFactory instance; static { instance = new BookingFactory(); } public static BookingFactory getInstance() { return instance; } private Boo
public class BookingFactory {
private final static BookingFactory instance;
static {
instance = new BookingFactory();
}
public static BookingFactory getInstance() {
return instance;
}
private BookingFactory() {
System.out.println("Object is created.");
}
}
public class Test {
BookingFactory instance = BookingFactory.getInstance();
instance = BookingFactory.getInstance();
Class<?> clazz = Class.forName("com.test.BookingFactory");
Constructor pvtConstructor = clazz.getDeclaredConstructors()[0];
// Set its access control
pvtConstructor.setAccessible(true);
// Invoke Private Constructor
BookingFactory notSingleton = (BookingFactory) pvtConstructor.newInstance(null);
}
公共类预订工厂{
私有最终静态BookingFactory实例;
静止的{
实例=新建BookingFactory();
}
公共静态BookingFactory getInstance(){
返回实例;
}
私人书厂(){
System.out.println(“对象已创建”);
}
}
公开课考试{
BookingFactory实例=BookingFactory.getInstance();
instance=BookingFactory.getInstance();
Class clazz=Class.forName(“com.test.BookingFactory”);
构造函数pvtConstructor=clazz.getDeclaredConstructors()[0];
//设置其访问控制
pvtConstructor.setAccessible(true);
//调用私有构造函数
BookingFactory notSingleton=(BookingFactory)pvtConstructor.newInstance(null);
}
当我运行这个程序时,我看到了不止一条打印出来的消息。是否有任何方法可以防止此单例从该反射中多次实例化
谢谢。在构造函数中进行断言:
private BookingFactory() {
if (instance != null)
throw new IllegalStateException("Only one instance may be created");
System.out.println("Object is created.");
}
我强烈建议阅读-使用枚举可以避免您所描述的内容,并且是在java中实现单例的推荐方法。尝试使用
枚举。枚举是很好的单例
public static enum BookingFactory {
INSTANCE;
public static BookingFactory getInstance() {
return INSTANCE;
}
}
无法通过反射创建枚举
getInstance()方法是多余的,但可以更轻松地运行测试,并引发以下异常:
java.lang.IllegalArgumentException: Cannot reflectively create enum objects
at java.lang.reflect.Constructor.newInstance(Constructor.java:530)
at MultiSingletonTest.main(MultiSingletonTest.java:40)
哦,看,有人已经给出了枚举的答案。无论如何都要发布以获得更多完整性。如果您的单例实际上没有存储状态,那么您最好的选择是不使用单例。相反,将工厂实现为无静态方法。改编自:
包服务器;
导入java.lang.reflect.ReflectPermission;
导入java.security.*;
公共类JavaSingleton{
私有静态JavaSingleton实例=null;
私有JavaSingleton(){
ReflectPermission perm=新的ReflectPermission(“suppressAccessChecks”,“suppressAccessChecks”);
AccessController.checkPermission(perm);
}
同步的公共静态最终JavaSingleton getInstance(){
if(实例==null){
AccessController.doPrivileged(新的PrivilegedAction(){
公共对象运行(){
INSTANCE=newjavasingleton();
返回null;
}
});
}
返回实例;
}
构造函数有一个检查,看看调用方是否有权访问它。正如链接所解释的,需要创建一个允许Singleton类本身调用构造函数的策略文件
Bohemian抛出异常的方法并不阻止客户端在调用getInstance()之前反射调用构造函数。即使它确保只创建一个实例,也不能保证这是由Singleton类“getInstance()
方法完成的
访问控制检查将防止这种不必要的实例化
import java.io.Serializable;
public class Singleton implements Serializable,Cloneable{
private static final long serialVersionUID = 1L;
private static Singleton singleton=null;
//private static volatile Singleton singleton=null;
private Singleton() {
if(singleton!=null){
throw new RuntimeException("Its Singleton Class use getInstance method for object creation");
}
}
public static Singleton getInstance(){
return Holder.singleton;
}
/****
* good way for getting the instance. No need to worry about
* BillPughSingleton
*/
private static class Holder{
private static final Singleton singleton=new Singleton();
}
/***
/*
* Use this code for preventing Singleton breakage in multi threading scenario and comment above getInstance method
* As this is the efficient way
* If we put synchronized at method level level then will impact performance and will executed every time when getInstance is called
* But if once the instance is created then there is no need for synchronized.
*/
/* public static Singleton getInstance(){
if(singleton==null){
synchronized (Singleton.class) {
if(singleton==null){
singleton=new Singleton();
}
}
}
return singleton;
}*/
@Override
public Object clone() throws CloneNotSupportedException{
/***
* We can place below check OR we can remove the exception thrown check and return singleton instead of super.clone()
* Use any one way
*/
if(singleton!=null){
throw new RuntimeException("Its Singleton Class use getInstance method for object creation");
}
return super.clone();
}
/***
*
* To Prevent breaking of singleton pattern by using serilization/de serilization
*/
private Object readResolve(){
System.out.println("Read Resolve executed");
return singleton;
}
}
**测试单态**
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
/***
*
* Ways to prevent break Singleton
*/
public class Main {
private static ObjectInputStream inputStream;
public static void main(String[] args) throws Exception {
Singleton orginalSingletonObject = Singleton.getInstance();
/***
* Singleton is broken by using Reflection
* We can prevent that by putting a check in private constructor of Singleton.java
*
*/
breakSingletonByReflection(orginalSingletonObject);
/***
* By Serialization/De-Serialization break Singleton We need
* Serialization interface in a class needs to be serialized like
* Singleton.java
*
* To prevent breaking of singleton we can add readResolve method in Singleton.java
* readResolve is the method which returns the instance of the class when a serialized class is de serialized.
* So implement the readResolve method to return the same object.
* Hence prevent breaking of Singleton design pattern.
* Refer this link for more information on readResolve
* https://docs.oracle.com/javase/6/docs/platform/serialization/spec/input.html#5903
*/
breakSingletonByserialization(orginalSingletonObject);
/***
* By Cloning break Singleton
* We need to implement Cloneable interface
* We can prevent that by putting a check in clone method of Singleton.java
*/
breakSingletonByCloning(orginalSingletonObject);
/***
* Break Singleton By thread
* This scenario is related to multi-threading environment
* We can do this by putting double lock mechanism in Singleton.java and its good practice to use Volatile
* We can also prevent this scenario of breaking by creating object eagerly but its not good to create object eagerly
*/
breakSingletonByThreading(orginalSingletonObject);
}
private static void breakSingletonByThreading(Singleton orginalSingletonObject) {
ExecutorService executorService=Executors.newFixedThreadPool(2);
/**
* Run this code snippet after commenting the other code for better understanding
* Run it repeatly to create a condition when 2 threads enter the method getInstance() of Singleton class at a same time
* When 2 threads enter the getInstance method at same time they will get the singleton object as null (private static Singleton singleton in Singleton.java)
* Then they will create two different objects ( have different hashcode) in this case singleton pattern will break.
*/
executorService.submit(Main::useSingleton); // JAVA 8 syntax it will get the singleton instance
executorService.submit(Main::useSingleton);
executorService.shutdown();
}
public static void useSingleton(){
Singleton singleton=Singleton.getInstance();
printSingletonData("By Threading", singleton);
}
private static void breakSingletonByCloning(Singleton orginalSingletonObject) throws CloneNotSupportedException {
Singleton clonedSingletonObject=(Singleton) orginalSingletonObject.clone();
printSingletonData("By Cloning", orginalSingletonObject, clonedSingletonObject);
}
private static void breakSingletonByReflection(Singleton orginalsingleton)
throws ClassNotFoundException, NoSuchMethodException,
InstantiationException, IllegalAccessException,
InvocationTargetException {
Class<?> singletonClass = Class.forName("SingletonTest.Singleton");
@SuppressWarnings("unchecked")
Constructor<Singleton> constructor = (Constructor<Singleton>) singletonClass
.getDeclaredConstructor();
constructor.setAccessible(true);
Singleton s = constructor.newInstance();
printSingletonData("By Reflection", orginalsingleton, s);
}
private static void breakSingletonByserialization(Singleton orginalsingleton)
throws FileNotFoundException, IOException, ClassNotFoundException {
/**
* Serialization
*/
ObjectOutputStream outputStream = new ObjectOutputStream(new FileOutputStream("E:\\Singleton.ser"));
outputStream.writeObject(orginalsingleton);
outputStream.close();
/**
* DeSerialization
*/
inputStream = new ObjectInputStream(new FileInputStream("E:\\Singleton.ser"));
Singleton deserializeObject = (Singleton) inputStream.readObject();
deserializeObject.hashCode();
printSingletonData("By Serialization", orginalsingleton, deserializeObject);
}
public static void printSingletonData(String operationName,
Singleton orginalsingleton, Singleton reflectionSigletonObject) {
System.out.println("------------------------------------------");
System.out.println("New Operation");
System.out.println(operationName);
System.out.println("orginal Hashcode=" + orginalsingleton.hashCode());
System.out.println("New Object hashcode="
+ reflectionSigletonObject.hashCode());
Boolean value = orginalsingleton.hashCode() != reflectionSigletonObject.hashCode();
System.out.println("These Object have different hascode. They are two different object Right = "
+ value);
System.out.println("As these are different Object this means Singleton Pattern is broken");
}
private static void printSingletonData(String operationName,Singleton singleton) {
System.out.println("------------------------------------------");
System.out.println("New Operation");
System.out.println(operationName);
System.out.println("Object hashcode=" + singleton.hashCode());
//System.out.println("As these are different Object this means Singleton Pattern is broken");
}
}
import java.io.FileInputStream;
导入java.io.FileNotFoundException;
导入java.io.FileOutputStream;
导入java.io.IOException;
导入java.io.ObjectInputStream;
导入java.io.ObjectOutputStream;
导入java.lang.reflect.Constructor;
导入java.lang.reflect.InvocationTargetException;
导入java.util.concurrent.ExecutorService;
导入java.util.concurrent.Executors;
/***
*
*防止单胎破裂的方法
*/
公共班机{
私有静态对象inputStream inputStream;
公共静态void main(字符串[]args)引发异常{
Singleton orginalSingletonObject=Singleton.getInstance();
/***
*Singleton是通过使用反射来打破的
*我们可以通过检查Singleton.java的私有构造函数来防止这种情况
*
*/
breakSingletonByReflection(原始SingleTonObject);
/***
*通过序列化/反序列化打破我们需要的单例
*类中的序列化接口需要像
*Singleton.java
*
*为了防止破坏singleton,我们可以在singleton.java中添加readResolve方法
*readResolve是在序列化类反序列化时返回该类实例的方法。
*因此,实现readResolve方法以返回相同的对象。
*因此,防止打破单例设计模式。
*有关readResolve的更多信息,请参阅此链接
* https://docs.oracle.com/javase/6/docs/platform/serialization/spec/input.html#5903
*/
breakSingletonByserialization(orginalSingletonObject);
/***
*通过克隆打破单身
*我们需要实现可克隆的接口
*我们可以通过检查Singleton.java的clone方法来防止这种情况
*/
breakSingletonByCloning(orginalSingletonObject);
/***
*断线
*此场景与多线程环境相关
*我们可以通过在Singleton.java中加入双锁机制以及使用Volatile的良好实践来实现这一点
*我们还可以通过急切地创建对象来防止这种情况,但急切地创建对象并不好
*/
breakSingletonByThreading(orginalSingletonObject);
}
私有静态void breakSingletonByThreading(Singleton orginalSingletonObject){
ExecutorService ExecutorService=Executors.newFixedThreadPool(2);
/**
*在注释其他代码后运行此代码段,以便更好地理解
*当两个线程同时进入Singleton类的getInstance()方法时,重复运行它以创建一个条件
*当两个线程同时进入getInstance方法时,它们会将singleton对象获取为null(singleton.java中的私有静态singleton singleton)
*然后,他们将创建两个不同的对象(具有不同的哈希代码),在这种情况下,单例模式将中断。
*/
executorService.submit(Main::useSingleton);//Java8语法它将获得singleton实例
executorService.submit(Main::useSingleton)
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
/***
*
* Ways to prevent break Singleton
*/
public class Main {
private static ObjectInputStream inputStream;
public static void main(String[] args) throws Exception {
Singleton orginalSingletonObject = Singleton.getInstance();
/***
* Singleton is broken by using Reflection
* We can prevent that by putting a check in private constructor of Singleton.java
*
*/
breakSingletonByReflection(orginalSingletonObject);
/***
* By Serialization/De-Serialization break Singleton We need
* Serialization interface in a class needs to be serialized like
* Singleton.java
*
* To prevent breaking of singleton we can add readResolve method in Singleton.java
* readResolve is the method which returns the instance of the class when a serialized class is de serialized.
* So implement the readResolve method to return the same object.
* Hence prevent breaking of Singleton design pattern.
* Refer this link for more information on readResolve
* https://docs.oracle.com/javase/6/docs/platform/serialization/spec/input.html#5903
*/
breakSingletonByserialization(orginalSingletonObject);
/***
* By Cloning break Singleton
* We need to implement Cloneable interface
* We can prevent that by putting a check in clone method of Singleton.java
*/
breakSingletonByCloning(orginalSingletonObject);
/***
* Break Singleton By thread
* This scenario is related to multi-threading environment
* We can do this by putting double lock mechanism in Singleton.java and its good practice to use Volatile
* We can also prevent this scenario of breaking by creating object eagerly but its not good to create object eagerly
*/
breakSingletonByThreading(orginalSingletonObject);
}
private static void breakSingletonByThreading(Singleton orginalSingletonObject) {
ExecutorService executorService=Executors.newFixedThreadPool(2);
/**
* Run this code snippet after commenting the other code for better understanding
* Run it repeatly to create a condition when 2 threads enter the method getInstance() of Singleton class at a same time
* When 2 threads enter the getInstance method at same time they will get the singleton object as null (private static Singleton singleton in Singleton.java)
* Then they will create two different objects ( have different hashcode) in this case singleton pattern will break.
*/
executorService.submit(Main::useSingleton); // JAVA 8 syntax it will get the singleton instance
executorService.submit(Main::useSingleton);
executorService.shutdown();
}
public static void useSingleton(){
Singleton singleton=Singleton.getInstance();
printSingletonData("By Threading", singleton);
}
private static void breakSingletonByCloning(Singleton orginalSingletonObject) throws CloneNotSupportedException {
Singleton clonedSingletonObject=(Singleton) orginalSingletonObject.clone();
printSingletonData("By Cloning", orginalSingletonObject, clonedSingletonObject);
}
private static void breakSingletonByReflection(Singleton orginalsingleton)
throws ClassNotFoundException, NoSuchMethodException,
InstantiationException, IllegalAccessException,
InvocationTargetException {
Class<?> singletonClass = Class.forName("SingletonTest.Singleton");
@SuppressWarnings("unchecked")
Constructor<Singleton> constructor = (Constructor<Singleton>) singletonClass
.getDeclaredConstructor();
constructor.setAccessible(true);
Singleton s = constructor.newInstance();
printSingletonData("By Reflection", orginalsingleton, s);
}
private static void breakSingletonByserialization(Singleton orginalsingleton)
throws FileNotFoundException, IOException, ClassNotFoundException {
/**
* Serialization
*/
ObjectOutputStream outputStream = new ObjectOutputStream(new FileOutputStream("E:\\Singleton.ser"));
outputStream.writeObject(orginalsingleton);
outputStream.close();
/**
* DeSerialization
*/
inputStream = new ObjectInputStream(new FileInputStream("E:\\Singleton.ser"));
Singleton deserializeObject = (Singleton) inputStream.readObject();
deserializeObject.hashCode();
printSingletonData("By Serialization", orginalsingleton, deserializeObject);
}
public static void printSingletonData(String operationName,
Singleton orginalsingleton, Singleton reflectionSigletonObject) {
System.out.println("------------------------------------------");
System.out.println("New Operation");
System.out.println(operationName);
System.out.println("orginal Hashcode=" + orginalsingleton.hashCode());
System.out.println("New Object hashcode="
+ reflectionSigletonObject.hashCode());
Boolean value = orginalsingleton.hashCode() != reflectionSigletonObject.hashCode();
System.out.println("These Object have different hascode. They are two different object Right = "
+ value);
System.out.println("As these are different Object this means Singleton Pattern is broken");
}
private static void printSingletonData(String operationName,Singleton singleton) {
System.out.println("------------------------------------------");
System.out.println("New Operation");
System.out.println(operationName);
System.out.println("Object hashcode=" + singleton.hashCode());
//System.out.println("As these are different Object this means Singleton Pattern is broken");
}
}