多classloader对单例模式的影响

早上看了一篇写单例模式的文章,总结的比较全,可惜仍然没有对单例模式在不同classloader甚至是多个jvm上的分析,在网上搜了一下,找到一个例子并改写如下:

定义一个空接口:
// Null interface, do nothing but you'll see the usage later
public interface IAntiSingleton {
}


定义一个通用的单例模式
public class AntiSingleton implements IAntiSingleton {
	private static final AntiSingleton instance = new AntiSingleton();

	public static AntiSingleton getInstance() {
		return instance;
	}
}


继承一个classloader并生成AntiSingleton对象
public class NewClassLoader extends ClassLoader {
	public IAntiSingleton createNewOne() throws Exception {
		InputStream is = getClass().getResourceAsStream("AntiSingleton.class");
		byte[] b = new byte[is.available()];
		is.read(b);
		Class clz = defineClass(null, b, 0, b.length);
		Object o = clz.newInstance();
		return (IAntiSingleton) o;
	}
}


测试方法:
public class TestAntiSingleton {
	public static void main(String[] args) throws Exception {
		AntiSingleton instance = AntiSingleton.getInstance();
		NewClassLoader loader = new NewClassLoader();
		IAntiSingleton newObj = loader.createNewOne();
		System.out.println(AntiSingleton.getInstance() == newObj);
	}
}
output:
=========
false


总结:

java中,一个类可以有多个定义,并且这些类名可以相同(但同一个类加载器产生类的类名不能相同)。如果不同类加载器两个类名相同,即使类的定义相同,甚至一个类的定义是由另一个类产生的,这两个类也是不同的类。

这也就是输出结果产生false的原因,因为此时两个类虽然名字相同,但是其实已经不是一个类。此时的单例模式,看起来是失效的。注意上面为什么要用接口,因为此时在程序中直接使用NewClassLoader用AntiSingleton对输出结果进行转型,在运行时就会抛出一个类型转换Exception。

可以想到的一种情况是,tomcat中,可以部署很多项目,各个项目中是可以出现相同的类名的,这就需要不同的classloader分别load生成这些类。

此外,GoF计划对“设计模式”进行修订,其中提到了要剔除“单例模式”,很期待修订版早点出来。

你可能感兴趣的:(设计模式,jvm,tomcat)