分享
 
 
 

Simply Singleton -- part1 By David Geary

王朝java/jsp·作者佚名  2006-01-09
窄屏简体版  字體: |||超大  

Use a registry

Use a singleton registry to:

Specify singleton classes at runtime

Prevent singleton subclasses from allowing multiple instances

Example 8 lists a singleton class that maintains a registry of singletons, registered by class name:

Example 8. A singleton with a registry

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

}

The preceding base class creates subclass instances and stores them in a map. But that base class is high maintenance because you must update its getInstance() method for every subclass. Luckily, we can use reflection to skirt that issue.

Use reflection

Example 9 lists a singleton with a registry that uses reflection to instantiate a particular class's objects. With this implementation, as opposed to Example 8, the Singleton.getInstance() method does not need to update when new subclasses are implemented.

Example 9. Use reflection to instantiate singletons

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;

}

}

One more thing concerning singleton registries: they should be encapsulated in their own class for maximum reuse.

Encapsulate the registry

Example 10 lists a singleton registry class:

Example 10. A SingletonRegistry class

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;

}

}

Notice I implemented the SingletonRegistry class as a singleton. I also generalized the registry so it can store and retrieve any type of object. Example 11 shows a Singleton class that uses the registry:

Example 11. A Singleton class that uses the registry

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);

}

}

The preceding Singleton class uses the registry's singleton instance to retrieve singleton objects by class name.

Now that we've seen how to implement thread-safe singletons and how to use a registry to specify singleton class names at runtime, let's examine how to deal with classloaders and serialization.

Classloaders

Because multiple classloaders are commonly used in many situations—including servlet containers—you can wind up with multiple singleton instances no matter how carefully you've implemented your singleton classes. If you want to make sure the same classloader loads your singletons, you must specify the classloader yourself; for example:

private static Class getClass(String classname)

throws ClassNotFoundException {

ClassLoader classLoader = Thread.currentThread().getContextClassLoader();

if(classLoader == null)

classLoader = Singleton.class.getClassLoader();

return (classLoader.loadClass(classname));

}

}

The preceding method tries to associate the classloader with the current thread; if that classloader is null, the method uses the same classloader that loaded a singleton base class. The preceding method can be used instead of Class.forName().

Serialization

If you serialize a singleton and then deserialize it twice, you will have two instances of your singleton, unless you implement the readResolve() method, like this:

Example 12. A serializable singleton

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.

}

private Object readResolve() {

return INSTANCE;

}

}

The previous singleton implementation returns the lone singleton instance from the readResolve() method; therefore, whenever the Singleton class is deserialized, it will return the same singleton instance.

Example 13 tests Example 12's singleton:

Example 13. Test a serializable singleton

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...");

writeSingleton();

Singleton s1 = readSingleton();

Singleton s2 = readSingleton();

Assert.assertEquals(true, s1 == s2);

}

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);

}

}

The preceeding test case serializes Example 12's singleton and deserializes it twice. Then the test case checks to see if the deserialized singletons are the same object. Here's the test case output:

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)

Singleton sign-off

The Singleton pattern is deceivingly simple, especially for Java developers. In this article, I've demonstrated how Java developers implement singletons, considering multithreading, classloaders, and serialization. I've also shown how you can implement singleton registries that let you specify singleton classes at runtime.

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
2023年上半年GDP全球前十五强
 百态   2023-10-24
美众议院议长启动对拜登的弹劾调查
 百态   2023-09-13
上海、济南、武汉等多地出现不明坠落物
 探索   2023-09-06
印度或要将国名改为“巴拉特”
 百态   2023-09-06
男子为女友送行,买票不登机被捕
 百态   2023-08-20
手机地震预警功能怎么开?
 干货   2023-08-06
女子4年卖2套房花700多万做美容:不但没变美脸,面部还出现变形
 百态   2023-08-04
住户一楼被水淹 还冲来8头猪
 百态   2023-07-31
女子体内爬出大量瓜子状活虫
 百态   2023-07-25
地球连续35年收到神秘规律性信号,网友:不要回答!
 探索   2023-07-21
全球镓价格本周大涨27%
 探索   2023-07-09
钱都流向了那些不缺钱的人,苦都留给了能吃苦的人
 探索   2023-07-02
倩女手游刀客魅者强控制(强混乱强眩晕强睡眠)和对应控制抗性的关系
 百态   2020-08-20
美国5月9日最新疫情:美国确诊人数突破131万
 百态   2020-05-09
荷兰政府宣布将集体辞职
 干货   2020-04-30
倩女幽魂手游师徒任务情义春秋猜成语答案逍遥观:鹏程万里
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案神机营:射石饮羽
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案昆仑山:拔刀相助
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案天工阁:鬼斧神工
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案丝路古道:单枪匹马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:与虎谋皮
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:李代桃僵
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:指鹿为马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:小鸟依人
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:千金买邻
 干货   2019-11-12
 
推荐阅读
 
 
 
>>返回首頁<<
 
靜靜地坐在廢墟上,四周的荒凉一望無際,忽然覺得,淒涼也很美
© 2005- 王朝網路 版權所有