上一篇文章介绍了单例模式的双重检测机制以及阻止通过反射破坏单例,传送门如下:
今天继续研究单例模式的几种高级模式,比如在Spring的 IOC机制中,是怎么来实现单例模式的?都知道IOC的意思是控制反转,通过IOC容器来管理Bean,当然也包括了Bean的实例化,他是怎么实现单例模式的呢?代码如下:
public class ContainerSingleton {
private ContainerSingleton() {}
//定义一个容器
private static Map<String, Object> ioc = new ConcurrentHashMap<String, Object>();
public static Object getInstance(String className) {
Object instance = null;
if(!ioc.containsKey(className)) {
//如果是第一次进入,就创建一个实例,并且放到容器中
try {
instance = Class.forName(className).newInstance();
ioc.put(className, instance);
} catch (Exception e) {
e.printStackTrace();
}
return instance;
} else {
return ioc.get(className);
}
}
}
测试代码:
public static void main(String[] args) {
Object instance1 = ContainerSingleton.getInstance("com.rq.pattern.TestVO");
Object instance2 = ContainerSingleton.getInstance("com.rq.pattern.TestVO");
System.out.println(instance1==instance2);
}
}
运行结果:
true
这里看到,通过这种方式,可以实现单例模式,那么会被反射的方式破坏吗?从技术上说,是可以的,测试代码如下:
public static void main(String[] args) {
// Object instance1 = ContainerSingleton.getInstance("com.rq.pattern.TestVO");
// Object instance2 = ContainerSingleton.getInstance("com.rq.pattern.TestVO");
// System.out.println(instance1==instance2);
//测试通过反射破坏容器式单例
Class<?> clazz = ContainerSingleton.class;
try {
Constructor<?> c = clazz.getDeclaredConstructor(null);
c.setAccessible(true);
Object newInstance1 = c.newInstance();
Object newInstance2 = c.newInstance();
System.out.println(newInstance1);
System.out.println(newInstance2);
} catch (Exception e) {
e.printStackTrace();
}
}
}
运行结果为:
com.rq.pattern.ContainerSingleton@6d06d69c
com.rq.pattern.ContainerSingleton@7852e922
可以看到,这种单例模式是可以被反射强制破坏的,那么为什么Spring的IOC还是要用这种方式来实现单例呢?可以这么理解:
因为IOC容器是一个生态,实例化是由IOC容器来管理的,他只负责他管理的单例是高效且线程安全的,在容器启动时就初始化了,后面只是调用,所以不存在线程安全的问题,不对他管理的生态外的负责,比如,在IOC中管理的类,你可以通过new的方式创建或者通过反射强制访问,代码编译不会报错,但是你无法使用new出来的对象。
Over。