JAVA ClassLoader实例和Singleton模式结合
来源:互联网 发布:ssm框架项目实例源码 编辑:程序博客网 时间:2024/04/29 11:53
使用注册表
使用一个单例类注册表可以:
在例8的单例类中,保持了一个通过类名进行注册的单例类注册表:
例8 带注册表的单例类
- import java.util.HashMap;
- import org.apache.log4j.Logger;
- public class Singleton {
- private static HashMap map = new HashMap();
- private static Logger logger = Logger.getRootLogger();
- protected Singleton() {
- // Exists only to thwart instantiation
- }
- public static synchronized Singleton getInstance(String classname) {
- if(classname == null) throw new IllegalArgumentException("Illegal classname");
- Singleton singleton = (Singleton)map.get(classname);
- if(singleton != null) {
- logger.info("got singleton from map: " + singleton);
- return singleton;
- }
- if(classname.equals("SingeltonSubclass_One"))
- singleton = new SingletonSubclass_One();
- else if(classname.equals("SingeltonSubclass_Two"))
- singleton = new SingletonSubclass_Two();
- map.put(classname, singleton);
- logger.info("created singleton: " + singleton);
- return singleton;
- }
- // Assume functionality follows that's attractive to inherit
- }
这段代码的基类首先创建出子类的实例,然后把它们存储在一个Map中。但是基类却得付出很高的代价因为你必须为每一个子类替换它的getInstance()方法。幸运的是我们可以使用反射处理这个问题。
使用反射
在例9的带注册表的单例类中,使用反射来实例化一个特殊的类的对象。与例8相对的是通过这种实现,Singleton.getInstance()方法不需要在每个被实现的子类中重写了。
例9 使用反射实例化单例类
- import java.util.HashMap;
- import org.apache.log4j.Logger;
- public class Singleton {
- private static HashMap map = new HashMap();
- private static Logger logger = Logger.getRootLogger();
- protected Singleton() {
- // Exists only to thwart instantiation
- }
- public static synchronized Singleton getInstance(String classname) {
- Singleton singleton = (Singleton)map.get(classname);
- if(singleton != null) {
- logger.info("got singleton from map: " + singleton);
- return singleton;
- }
- try {
- singleton = (Singleton)Class.forName(classname).newInstance();
- }
- catch(ClassNotFoundException cnf) {
- logger.fatal("Couldn't find class " + classname);
- }
- catch(InstantiationException ie) {
- logger.fatal("Couldn't instantiate an object of type " + classname);
- }
- catch(IllegalAccessException ia) {
- logger.fatal("Couldn't access class " + classname);
- }
- map.put(classname, singleton);
- logger.info("created singleton: " + singleton);
- return singleton;
- }
- }
关于单例类的注册表应该说明的是:它们应该被封装在它们自己的类中以便最大限度的进行复用。
封装注册表
例10列出了一个单例注册表类。
例10 一个SingletonRegistry类
- import java.util.HashMap;
- import org.apache.log4j.Logger;
- public class SingletonRegistry {
- public static SingletonRegistry REGISTRY = new SingletonRegistry();
- private static HashMap map = new HashMap();
- private static Logger logger = Logger.getRootLogger();
- protected SingletonRegistry() {
- // Exists to defeat instantiation
- }
- public static synchronized Object getInstance(String classname) {
- Object singleton = map.get(classname);
- if(singleton != null) {
- return singleton;
- }
- try {
- singleton = Class.forName(classname).newInstance();
- logger.info("created singleton: " + singleton);
- }
- catch(ClassNotFoundException cnf) {
- logger.fatal("Couldn't find class " + classname);
- }
- catch(InstantiationException ie) {
- logger.fatal("Couldn't instantiate an object of type " +
- classname);
- }
- catch(IllegalAccessException ia) {
- logger.fatal("Couldn't access class " + classname);
- }
- map.put(classname, singleton);
- return singleton;
- }
- }
注意我是把SingletonRegistry类作为一个单例模式实现的。我也通用化了这个注册表以便它能存储和取回任何类型的对象。例11显示了的Singleton类使用了这个注册表。
例11 使用了一个封装的注册表的Singleton类
- import java.util.HashMap;
- import org.apache.log4j.Logger;
- public class Singleton {
- protected Singleton() {
- // Exists only to thwart instantiation.
- }
- public static Singleton getInstance() {
- return (Singleton)SingletonRegistry.REGISTRY.getInstance(classname);
- }
- }
这里不晓得是作者搞忘了,还是有其他什么原因
上面的Singleton类使用那个注册表的唯一实例通过类名取得单例对象。
现在我们已经知道如何实现线程安全的单例类和如何使用一个注册表去在运行期指定单例类名,接着让我们考查一下如何安排类载入器和处理序列化。
Classloaders
在许多情况下,使用多个类载入器是很普通的--包括servlet容器--所以不管你在实现你的单例类时是多么小心你都最终可以得到多个单例类的实例。如果你想要确保你的单例类只被同一个的类载入器装入,那你就必须自己指定这个类载入器;例如:
- private static Class getClass(String classname)
- throws ClassNotFoundException {
- ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
- if(classLoader == null)
- classLoader = Singleton.class.getClassLoader();
- return (classLoader.loadClass(classname));
- }
- }
这个方法会尝试把当前的线程与那个类载入器相关联;如果classloader为null,这个方法会使用与装入单例类基类的那个类载入器。这个方法可以用Class.forName()代替(这里还有疑问的哈,据Jdon上面一篇文章说这样不对,还不能理解其中的意思,请大家说为什么?Jdon相关讨论地址http://www.jdon.com/jive/article.jsp?forum=91&thread=15456)。
序列化
如果你序列化一个单例类,然后两次重构它,那么你就会得到那个单例类的两个实例,除非你实现readResolve()方法,像下面这样:
例12 一个可序列化的单例类
- import org.apache.log4j.Logger;
- public class Singleton implements java.io.Serializable {
- public static Singleton INSTANCE = new Singleton();
- protected Singleton() {
- // Exists only to thwart instantiation.
- }
- [b] private Object readResolve() {
- return INSTANCE;
- }[/b]}
上面的单例类实现从readResolve()方法中返回一个唯一的实例;这样无论Singleton类何时被重构,它都只会返回那个相同的单例类实例。
例13测试了例12的单例类:
例13 测试一个可序列化的单例类
- import java.io.*;
- import org.apache.log4j.Logger;
- import junit.framework.Assert;
- import junit.framework.TestCase;
- public class SingletonTest extends TestCase {
- private Singleton sone = null, stwo = null;
- private static Logger logger = Logger.getRootLogger();
- public SingletonTest(String name) {
- super(name);
- }
- public void setUp() {
- sone = Singleton.INSTANCE;
- stwo = Singleton.INSTANCE;
- }
- public void testSerialize() {
- logger.info("testing singleton serialization...");
- [b] writeSingleton();
- Singleton s1 = readSingleton();
- Singleton s2 = readSingleton();
- Assert.assertEquals(true, s1 == s2);[/b] }
- private void writeSingleton() {
- try {
- FileOutputStream fos = new FileOutputStream("serializedSingleton");
- ObjectOutputStream oos = new ObjectOutputStream(fos);
- Singleton s = Singleton.INSTANCE;
- oos.writeObject(Singleton.INSTANCE);
- oos.flush();
- }
- catch(NotSerializableException se) {
- logger.fatal("Not Serializable Exception: " + se.getMessage());
- }
- catch(IOException iox) {
- logger.fatal("IO Exception: " + iox.getMessage());
- }
- }
- private Singleton readSingleton() {
- Singleton s = null;
- try {
- FileInputStream fis = new FileInputStream("serializedSingleton");
- ObjectInputStream ois = new ObjectInputStream(fis);
- s = (Singleton)ois.readObject();
- }
- catch(ClassNotFoundException cnf) {
- logger.fatal("Class Not Found Exception: " + cnf.getMessage());
- }
- catch(NotSerializableException se) {
- logger.fatal("Not Serializable Exception: " + se.getMessage());
- }
- catch(IOException iox) {
- logger.fatal("IO Exception: " + iox.getMessage());
- }
- return s;
- }
- public void testUnique() {
- logger.info("testing singleton uniqueness...");
- Singleton another = new Singleton();
- logger.info("checking singletons for equality");
- Assert.assertEquals(true, sone == stwo);
- }
- }
前面这个测试案例序列化例12中的单例类,并且两次重构它。然后这个测试案例检查看是否被重构的单例类实例是同一个对象。下面是测试案例的输出:
- Buildfile: build.xml
- init:
- [echo] Build 20030422 (22-04-2003 11:32)
- compile:
- run-test-text:
- [java] .INFO main: testing singleton serialization...
- [java] .INFO main: testing singleton uniqueness...
- [java] INFO main: checking singletons for equality
- [java] Time: 0.1
- [java] OK (2 tests)
单例模式结束语
单例模式简单却容易让人迷惑,特别是对于Java的开发者来说。在这篇文章中,作者演示了Java开发者在顾及多线程、类载入器和序列化情况如何实现单例模式。作者也展示了你怎样才能实现一个单例类的注册表,以便能够在运行期指定单例类。
- JAVA ClassLoader实例和Singleton模式结合
- singleton 模式的cpp实现和实例
- 单实例模式(Singleton)
- java语言讲解singleton的编程思想---深入浅出单实例Singleton设计模式
- 单实例设计模式(Singleton)
- 单实例Singleton设计模式
- java自定义ClassLoader实例代码
- java Singleton模式
- java Singleton模式
- Java模式之Singleton
- java Singleton模式
- java Singleton模式
- java 基本Singleton模式
- java 同步Singleton模式
- java Singleton模式工厂
- java设计模式--Singleton
- JAVA中的Singleton模式
- java singleton 单体模式
- 四种方案解决Form之间相互访问、参数传递的问题
- 用java学习OpenGL的环境配置
- 怎样将Excel中的某一部分字段内容导入到SQL Server 2000的某个表的某些字段中
- 本博客准备搬家
- confirm
- JAVA ClassLoader实例和Singleton模式结合
- x86 CPU的操作模式
- .NET 中 解释及用法
- 使用注册表/组策略/批处理禁用声卡
- 战将宣言
- 快速排序
- Eclipse开发资料汇总
- 直接排序
- MindManager