kapok
垃圾桶,嘿嘿,我藏的这么深你们还能找到啊,真牛!
BlogJava
::
首页
::
新随笔
::
联系
::
聚合
::
管理
::
455 随笔 :: 0 文章 :: 76 评论 :: 0 Trackbacks
<
2005年4月
>
日
一
二
三
四
五
六
27
28
29
30
31
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
1
2
3
4
5
6
7
常用链接
我的随笔
我的评论
我的参与
最新评论
留言簿
(28)
给我留言
查看公开留言
查看私人留言
随笔分类
.NET(10)
(rss)
ALL(464)
(rss)
AppFuse(20)
(rss)
CorBa(2)
(rss)
Eclipse技巧和插件等(7)
(rss)
English(10)
(rss)
ERP(3)
(rss)
HibernateAndSpring(82)
(rss)
J2EE(290)
(rss)
J2SE(27)
(rss)
JB(2)
(rss)
JBOSS(4)
(rss)
JDO(1)
(rss)
Linux(7)
(rss)
Oracle(9)
(rss)
PetStore
(rss)
Struts(9)
(rss)
UML与RUP(13)
(rss)
Web Services(8)
(rss)
Weblogic Portal(72)
(rss)
XDoclet(6)
(rss)
个人项目所需资料(8)
(rss)
办公自动化(2)
(rss)
点滴(1)
(rss)
程序员生活(10)
(rss)
行业知识(15)
(rss)
软件工程和项目管理(32)
(rss)
软件测试(1)
(rss)
随手贴(5)
(rss)
面试(4)
(rss)
随笔档案
2005年9月 (18)
2005年8月 (39)
2005年7月 (42)
2005年6月 (49)
2005年5月 (70)
2005年4月 (116)
2005年3月 (121)
Corba
EAI
Bea Portal相关
dnnchina
Enterprise Java Research Library
xoops
泡泡-博客
Online Document
Bea Resource Center
WebLogic Online Help_ZH
Open Source
exo portal
Groller
Mule
pow2toolkit
xpetstore
开源
Portal
huihoo JSR168
灰狐
RSS Links
.Text 0.958 安装&问题解决方案
All about Blog and RSS
RSS links
Weblogic净化贴
Weblogic
WL Portal FAQs
WLP FAQss
不错的链接
chenyun2000
CSDN专栏作家
Eclipse Live Forum
firebody
gigix
glchengang
IT人
JavaEye
JavaPassion
michael
ODMG
oracle_tech
Pattern在线查询手册
querycriteria
rosen
spring reference
上海电子地图
兔八哥
兔子
思维导图
范凯的废纸篓
工具集合
AppFuse
数据仓库相关
blog on dw
BRM业务参考模型
chinabi
china-bi
CNOUG DW
datawarehouse
dbazine
dmreview
DW 信息目录
dw-institute
DWWAY
ewsolutions
flymouse
inmoncif
intelligententerprise
isomebody
IT售前论坛
rkimball
SummerRain
tdan
商业智能
头头脑脑
快语综合
精进门
搜索
最新评论
1. re: Java中的URLEncoder和URLDecoder类
asdfsdf
--sadf
2. re: 面试题,做出来3万月薪[未登录]
很强,就是这样的逻辑@此外
--TEST
3. re: MKS Toolkit[未登录]
政治
--s
4. re: Java 远程方法调用(RMI)
if (r instanceof Meeting )
这个Meeting从哪里来?
--nx
5. re: ClearCase指南-基础篇(连载一)
clearcase 可以使用clearfsimport -recurse -nsetevent进行批量导入
--china-java.net
阅读排行榜
1. weblogic部署方法(11445)
2. x509数字证书介绍(11411)
3. 一个很不错的基于角色的权限管理系统设计!(10485)
4. UML的StereoType的解释(8996)
5. When Runtime.exec() won't (5430)
6. 完全卸载Oracle(5392)
7. OpenLDAP快速指南(5097)
8. 如何发布和查找 WSDL 服务描述(4487)
9. Eclipse不能自动编译的问题(4275)
10. SSL※ X509(3867)
评论排行榜
1. 面试题,做出来3万月薪(11)
2. x509数字证书介绍(5)
3. OpenLDAP快速指南(5)
4. Compiere的汉化 (5)
5. oracle的select for update(4)
6. 使用Eclipse plus Pluto开发你的第一个与JSR168兼容的Portlet(3)
7. 迎接RFID的时代(3)
8. 简化JavaMail:小巧 Jakarta Commons-Email 简单教程(3)
9. Visual CHM和jd2chm不错(2)
10. Java 远程方法调用(RMI)(2)
单例模式完全剖析(3)---- 探究简单却又使人迷惑的单例模式
http://www.uml.org.cn/j2ee/200501241.htm
单例模式完全剖析(3)---- 探究简单却又使人迷惑的单例模式
kevin 翻译 选自:java研究组织
使用注册表
使用一个单例类注册表可以:
在运行期指定单例类
防止产生多个单例类子类的实例
在例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()代替。
序列化
如果你序列化一个单例类,然后两次重构它,那么你就会得到那个单例类的两个实例,除非你实现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开发者在顾及多线程、类载入器和序列化情况如何实现单例模式。作者也展示了你怎样才能实现一个单例类的注册表,以便能够在运行期指定单例类。
posted on 2005-04-18 14:33
笨笨
阅读(326)
评论(0)
编辑
收藏
所属分类:
J2EE
、
ALL
、
J2SE
新用户注册
刷新评论列表
只有注册用户
登录
后才能发表评论。
网站导航:
博客园
IT新闻
知识库
C++博客
博问
相关文章:
简化JavaMail:小巧 Jakarta Commons-Email 简单教程
读"Under the Hood of J2EE Clustering" J2EE集群
Phase
x509数字证书介绍
SSL※ X509
了解安全性断言标记语言
架构蓝图--软件架构 "4+1" 视图模型
主动对象
Profile,Stereotype,TaggedValue与OCL漫谈
Drools 为你的业务逻辑提供框架(翻译)
Powered by:
BlogJava
Copyright © 笨笨