`
lh870003574
  • 浏览: 24043 次
  • 性别: Icon_minigender_1
  • 来自: 广州
社区版块
存档分类
最新评论

StringManager与单例模式

阅读更多

    tomcat 源代码中,有这样一个实用类: org.apache.catalina.util.StringManager,基本上每个tomcat组件(如:connector, container, realm, loader, logger等)都会用到它。这是一个管理异常消息的helper class

 

    tomcat这样的Servlet容器,异常消息无论是对系统管理员或者程序员都非常重要。管理员可以通过异常消息,快速定位错误。而对于程序异常,tomcat将异常消息封装到ServletException,来告知程序员Servlet中的错误。

 

    Tomcat如何管理这些异常消息呢?第一个要排除的是硬编码在代码中。这是十分不规范的做法,每一次编辑消息都要重新编译代码,非常麻烦。 Tomcat 将这些消息存入properties文件中,方便编辑。而且利用javaResourceBundle类,可以方便的实现国际化,要知道tomcat是一个使用非常广泛的Servlet容器。然而,tomcat的核心包就有几百个类,如果将这些类要用到的异常消息存入一个properties文件,无疑会带来维护上的噩梦。

 

    Tomcat的做法是一个包共用一个properties文件,如果大家机器上安装有tomcat,可以打开%TOMCAT_HOME%/server/libcatalina.jar(tomcat最核心的包,catalinatomcat的代号)看看,会发现里面基本上每一个包都含有LocalString.properties文件,如:org.apache.core,就是这些文件,存储了tomcat所要用到的异常消息。

 

    StringManager就是为了处理这些异常消息的helper class, 当包中的某个类需要用到异常消息时,可以先实例化StringManager,然后调用getString(String key)方法

 

sm.getString("httpConnector.alreadyInitialized")

上面的语句返回“HTTP connector has already been initialized

如果你有LocalStrings_CN.properties文件,则会返回相应的中文消息。

 

    然而,若每个类都实例化一个StringManager对象,而这些对象所包含的异常消息都是相同的,同样也会带来资源上的浪费。若每个包中的类,都共用一个StringManager对象,则会大大的提高效率。怎么做到这一点呢?读到这里,相信熟悉设计模式的读者应该都会想到了吧~  没错,就是单例模式。

   

单例

         单例模式是对象的创建模式,确保一个类只有一个实例,而且自行实例化并向整个系统提供这个实例。

 

/**
 * 单例模式
 * @author linhai
 */
public class Singleton {
	
	//声明一个静态的实例
	private static Singleton instance;
	
	//私有化构造函数
	private Singleton(){}
	
	//静态方法返回自身实例
	public static Singleton getInstance()
	{
		if(instance==null)
		{
			instance=new Singleton();
		}
		return instance;
	}

}

 

 

 

    上面的代码便是单例模式的经典示例。单例的要点有二:一是私有化构造函数,这样其它的类不能进行实行化,保证单例,第二是要提供静态的工厂方法,返回自身实例,让客户端调用:Singleton instance=Singleton.getInstance()

 

 

  

 

 

 

StringManager

         明白了单例模式,要实现一个包只有一个StringManager对象便简单了,可以采用一个Map(tomcat 采用的是HashTable),以包名作为keyStringManager实例作为value

 

package com.scnulh.catalina.util;

import java.text.MessageFormat;
import java.util.HashMap;
import java.util.Map;
import java.util.MissingResourceException;
import java.util.ResourceBundle;

public class StringManager {
	
	/**
	 * ResourceBundle实例,代表存储tomcat异常消息的资源文件
	 */
	private ResourceBundle bundle;
	
	/**
	 * 保存StringManager对象的Map,以包名为key,value为StringManager对象
	 */
	private static Map<String, StringManager> stringManagers=
		new HashMap<String, StringManager>();
	
	/**
	 * 私有化的构造函数
	 * @param packageName  包名
	 */
	private StringManager(String packageName)
	{
		//包名加LocalStrings,这也是为什么我们看的资源文件是以LocalStrings命名的原因
		String baseName=packageName+".LocalStrings";
		//根据包名,获取资源文件
		bundle=ResourceBundle.getBundle(baseName);
	}
	
	/**
	 * 返回StringManager实例的静态方法,确保相同的包名返回相同的实例
	 * 同步方法	
	 * @param packageName  包名
	 * @return
	 */
	public synchronized static StringManager getStringManager(String packageName)
	{
		//先从map中查找
		StringManager stringManager=stringManagers.get(packageName);
		
		//如果对应包的StringManager未实例化,则实例化,并且放入Map中缓存
		if(stringManager==null)
		{
			stringManager=new StringManager(packageName);
			stringManagers.put(packageName, stringManager);
		}
		return stringManager;
	}
	
	
	//============以下为StringManager对象查找异常消息的方法===========
	public String getString(String key)
	{
		//对参数先进行验证
		if(key==null)
		{
			String msg="key is null";
			throw new NullPointerException(msg);
		}
		String result=null;
		try
		{
			result=bundle.getString(key);
		}
		catch(MissingResourceException e)
		{
			result="can not find message with the key "+key;
		}
		
		return result;
	}
	
	public String getString(String key,Object[] args)
	{
		String result=null;
		String initMessage=getString(key);
		
		try
		{
			Object[] notNullArgs=args;
			for(int i=0;i<args.length;i++)
			{
				if(args[i]==null)
				{
					if(notNullArgs==args)
						notNullArgs=(Object[])args.clone();
					args[i]="null";
				}
			}
			//MessageFormat的使用
			result=MessageFormat.format(initMessage, notNullArgs);
		}
		//这里异常的处理值得我们学习
		//估计大部分的程序员都会直接来一句iae.printStackTrace();吧
		catch(IllegalArgumentException iae)
		{
			StringBuilder sb=new StringBuilder();
			sb.append(initMessage);
			for (int i = 0; i < args.length; i++) {
                sb.append(" arg[" + i + "]=" + args[i]);
            }
			result=sb.toString();
			
		}
		return result;
	}
	//以下是方法的重载,方便客户端的调用
	public String getString(String key,Object arg)
	{
		Object[] args=new Object[]{arg};
		return getString(key, args);
	}
	
	public String getString(String key,Object arg1,Object arg2)
	{
		Object[] args=new Object[]{arg1,arg2};
		return getString(key, args);
	}
	public String getString(String key,Object arg1,Object arg2,
			Object arg3)
	{
		Object[] args=new Object[]{arg1,arg2,arg3};
		return getString(key, args);
	}
	public String getString(String key,Object arg1,Object arg2,
			Object arg3,Object arg4)
	{
		Object[] args=new Object[]{arg1,arg2,arg3,arg4};
		return getString(key, args);
	}
	
	public static void main(String[] args)
	{
		StringManager stringManager=
			StringManager.getStringManager("ex03.pyrmont.connector.http");
		String string=stringManager.getString("httpConnector.alreadyInitialized");	
		
		System.out.println(string);
		
		string=stringManager.getString("httpConnector.anAddress", "192.165.23.26",12);
		System.out.println(string);

	}

}

 

 

1
5
分享到:
评论
3 楼 lh870003574 2012-08-30  
liuyes 写道
//以下是方法的重载,避免都调用getString(String key,Object[] args)  
//效率会更高

这个效率会高?(什么效率?)应该写方便使用吧,呵呵

看的挺认真的~~你说的对,以下那几个重载的方法都调用了getString(String key,Object[] args)  不是为了提高效率,而是为了调用的方便。
之所以写这两行注释,是因为我看错了,以为和java的可变形参有关,而可变形参对性能确实有点影响~  已经改过来了,谢谢提醒~
2 楼 liuyes 2012-08-30  
//以下是方法的重载,避免都调用getString(String key,Object[] args)  
//效率会更高

这个效率会高?(什么效率?)应该写方便使用吧,呵呵
1 楼 sconio 2012-08-30  
谢谢分享,值得学习一下

相关推荐

    ChineseStringManager

    这种设计模式在iOS开发中非常常见,可以提高代码的复用性和灵活性。 在实际应用中,例如地图定位服务,用户可能输入中文地点名进行搜索,ChineseStringManager可以将这些中文字符串转换为拼音,然后与地图服务提供...

    StringManager

    字符串管理器 核心:可运行类 ru.ifmo.ctddev.elite.core.CoreStarter &lt;数据库的文件名&gt; 数据库文件必须存在(至少为空)。 添加一名作者 编辑器:ru.ifmo.ctddev.elite.editor.StringEditor ...

    跟我学汉化(含gif动画)汉化新世纪官方作品

     (6)NSIS (7)StringManager (8)Passlo (9)AutoFontSet (10)Sisulizer  (11)灵便汉化编辑器 (12)VBLocalize (13)FreeRes (14)PE-scan (15)DictionaryHelper  (16)ExeinfoPE (17)点睛字符替换器 (18)ResHacker (19)...

    SocketInputStream.java

    * $Header: /home/cvs/jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/util/StringManager.java,v 1.2 2001/07/22 20:25:14 pier Exp $ * $Revision: 1.2 $ * $Date: 2001/07/22 20:25:14 $ * * =...

    propbank annotation tools2

    3. **StringManager类**: - 用于管理和处理字符串对象,可能包括字符串的拼接、分割、替换等操作。 - 在语义标注过程中,字符串管理是非常关键的一环,例如处理复杂的命名实体识别、同义词替换等。 #### 使用...

    C# 常用类代码(封装)

    1.DataValidator.cs 数据验证类,提供如...21.StringManager 字符串管理类 22.UploadFile 提供上传文件时所使用的方法 23.UploadFileManager 文件上传管理类 24.ValidateCode 可以生成验证码图像的类,图像格式为gif

    QtTreePropertyBrowser简单演示

    为了使QtTreePropertyBrowser能够显示和编辑实际对象的属性,我们需要将这些属性与对象关联起来。这通常通过使用QtVariantPropertyManager和QtObjectPropertyManager来实现。 5. **事件处理** ...

    how-tomcat-works(中文版).pdf

    重点讲解了StringManager类的作用,以及如何启动应用和配置连接器。 ### 第4章:Tomcat的默认连接器 这一章重点讲解了Tomcat的默认连接器实现——HttpConnector类。分析了HTTP/1.1协议的新特性,如持久化连接、...

    c#字符祖玛游戏

    总的来说,C#字符祖玛游戏的开发涵盖了C#语言的基础知识和高级特性,包括字符串操作、循环与条件判断、事件处理以及面向对象编程思想。通过实践这样的项目,开发者不仅可以巩固C#语法,还能提升算法设计和问题解决的...

    how tomcat works

    #### 一、简介与概览 Tomcat作为一款开源的Servlet容器,被广泛应用于Java Web开发之中。它不仅能够运行Java Servlet,还支持JSP技术,是学习Java Web开发的理想平台之一。本文将深入探讨Tomcat的工作原理,包括其...

    ValueInternals..

    class StringManager { public: char* safe_strdup(const char *s) { if (s == NULL) { return NULL; } size_t len = strlen(s) + 1; char *copy = (char*)malloc(len); if (copy != NULL) { memcpy(copy, s...

    tomcat源码解析

    #### 简介与概览 Tomcat作为一款开源的Servlet容器,被广泛应用于Java Web应用的开发与部署环境中。它不仅支持Servlet API,还支持JSP规范,使得开发者能够轻松地构建动态网页。本文旨在深入分析Tomcat的工作原理...

    tomcat工作原理(中文版)

    - **StringManager类**:用于国际化和本地化的字符串管理工具。 - **Application1**:实现一个简单的连接器示例,包括SocketInputStream、HttpRequest对象的创建及解析过程。 - **HttpResponse对象**:解析请求并...

    《深入剖析Tomcat(中文版+英文版)》.rar

    3.1 stringmanager类 3.2 应用程序 3.2.1 启动应用程序 3.2.2 httpconnector类 3.2.3 创建httprequest对象 3.2.4 创建httpresponse对象 3.2.5 静态资源处理器和servlet处理器 3.2.6 运行应用程序 3.3 小结 ...

    java入门学习

    Java与C语言的主要区别在于数据类型的表示范围不同,Java支持更大的数值范围。 - **常用数据类型**:主要包括`int`(整型)、`double`(双精度浮点型)、`boolean`(布尔型)、`byte`(字节型)等。值得注意的是`...

    How Tomcat Works: A Guide to Developing Your Own Java Servlet Container

    3.2 StringManager类 11 3.3 Application 12 3.3.1 启动 13 3.3.2 connector 13 3.3.3 创建HttpRequest对象 13 3.3.3.1 SocketInputStream类 14 3.3.3.2 解析请求行(request line) 14 3.3.3.3 解析请求头(request...

Global site tag (gtag.js) - Google Analytics