君子博学而日参省乎己 则知明而行无过矣

博客园 首页 新随笔 联系 订阅 管理

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

 

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

 

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

 

    Tomcat的做法是一个包共用一个properties文件,如果大家机器上安装有tomcat,可以打开%TOMCAT_HOME%/server/lib的catalina.jar(tomcat最核心的包,catalina是tomcat的代号)看看,会发现里面基本上每一个包都含有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对象,则会大大的提高效率。怎么做到这一点呢?读到这里,相信熟悉设计模式的读者应该都会想到了吧~  没错,就是单例模式。

   

单例

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

 

Java代码  收藏代码
  1. /** 
  2.  * 单例模式 
  3.  * @author linhai 
  4.  */  
  5. public class Singleton {  
  6.       
  7.     //声明一个静态的实例  
  8.     private static Singleton instance;  
  9.       
  10.     //私有化构造函数  
  11.     private Singleton(){}  
  12.       
  13.     //静态方法返回自身实例  
  14.     public static Singleton getInstance()  
  15.     {  
  16.         if(instance==null)  
  17.         {  
  18.             instance=new Singleton();  
  19.         }  
  20.         return instance;  
  21.     }  
  22.   
  23. }  

 

 

 

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

 

 

  

 

 

 

StringManager

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

 

Java代码  收藏代码
  1. package com.scnulh.catalina.util;  
  2.   
  3. import java.text.MessageFormat;  
  4. import java.util.HashMap;  
  5. import java.util.Map;  
  6. import java.util.MissingResourceException;  
  7. import java.util.ResourceBundle;  
  8.   
  9. public class StringManager {  
  10.       
  11.     /** 
  12.      * ResourceBundle实例,代表存储tomcat异常消息的资源文件 
  13.      */  
  14.     private ResourceBundle bundle;  
  15.       
  16.     /** 
  17.      * 保存StringManager对象的Map,以包名为key,value为StringManager对象 
  18.      */  
  19.     private static Map<String, StringManager> stringManagers=  
  20.         new HashMap<String, StringManager>();  
  21.       
  22.     /** 
  23.      * 私有化的构造函数 
  24.      * @param packageName  包名 
  25.      */  
  26.     private StringManager(String packageName)  
  27.     {  
  28.         //包名加LocalStrings,这也是为什么我们看的资源文件是以LocalStrings命名的原因  
  29.         String baseName=packageName+".LocalStrings";  
  30.         //根据包名,获取资源文件  
  31.         bundle=ResourceBundle.getBundle(baseName);  
  32.     }  
  33.       
  34.     /** 
  35.      * 返回StringManager实例的静态方法,确保相同的包名返回相同的实例 
  36.      * 同步方法  
  37.      * @param packageName  包名 
  38.      * @return 
  39.      */  
  40.     public synchronized static StringManager getStringManager(String packageName)  
  41.     {  
  42.         //先从map中查找  
  43.         StringManager stringManager=stringManagers.get(packageName);  
  44.           
  45.         //如果对应包的StringManager未实例化,则实例化,并且放入Map中缓存  
  46.         if(stringManager==null)  
  47.         {  
  48.             stringManager=new StringManager(packageName);  
  49.             stringManagers.put(packageName, stringManager);  
  50.         }  
  51.         return stringManager;  
  52.     }  
  53.       
  54.       
  55.     //============以下为StringManager对象查找异常消息的方法===========  
  56.     public String getString(String key)  
  57.     {  
  58.         //对参数先进行验证  
  59.         if(key==null)  
  60.         {  
  61.             String msg="key is null";  
  62.             throw new NullPointerException(msg);  
  63.         }  
  64.         String result=null;  
  65.         try  
  66.         {  
  67.             result=bundle.getString(key);  
  68.         }  
  69.         catch(MissingResourceException e)  
  70.         {  
  71.             result="can not find message with the key "+key;  
  72.         }  
  73.           
  74.         return result;  
  75.     }  
  76.       
  77.     public String getString(String key,Object[] args)  
  78.     {  
  79.         String result=null;  
  80.         String initMessage=getString(key);  
  81.           
  82.         try  
  83.         {  
  84.             Object[] notNullArgs=args;  
  85.             for(int i=0;i<args.length;i++)  
  86.             {  
  87.                 if(args[i]==null)  
  88.                 {  
  89.                     if(notNullArgs==args)  
  90.                         notNullArgs=(Object[])args.clone();  
  91.                     args[i]="null";  
  92.                 }  
  93.             }  
  94.             //MessageFormat的使用  
  95.             result=MessageFormat.format(initMessage, notNullArgs);  
  96.         }  
  97.         //这里异常的处理值得我们学习  
  98.         //估计大部分的程序员都会直接来一句iae.printStackTrace();吧  
  99.         catch(IllegalArgumentException iae)  
  100.         {  
  101.             StringBuilder sb=new StringBuilder();  
  102.             sb.append(initMessage);  
  103.             for (int i = 0; i < args.length; i++) {  
  104.                 sb.append(" arg[" + i + "]=" + args[i]);  
  105.             }  
  106.             result=sb.toString();  
  107.               
  108.         }  
  109.         return result;  
  110.     }  
  111.     //以下是方法的重载,方便客户端的调用  
  112.     public String getString(String key,Object arg)  
  113.     {  
  114.         Object[] args=new Object[]{arg};  
  115.         return getString(key, args);  
  116.     }  
  117.       
  118.     public String getString(String key,Object arg1,Object arg2)  
  119.     {  
  120.         Object[] args=new Object[]{arg1,arg2};  
  121.         return getString(key, args);  
  122.     }  
  123.     public String getString(String key,Object arg1,Object arg2,  
  124.             Object arg3)  
  125.     {  
  126.         Object[] args=new Object[]{arg1,arg2,arg3};  
  127.         return getString(key, args);  
  128.     }  
  129.     public String getString(String key,Object arg1,Object arg2,  
  130.             Object arg3,Object arg4)  
  131.     {  
  132.         Object[] args=new Object[]{arg1,arg2,arg3,arg4};  
  133.         return getString(key, args);  
  134.     }  
  135.       
  136.     public static void main(String[] args)  
  137.     {  
  138.         StringManager stringManager=  
  139.             StringManager.getStringManager("ex03.pyrmont.connector.http");  
  140.         String string=stringManager.getString("httpConnector.alreadyInitialized");    
  141.           
  142.         System.out.println(string);  
  143.           
  144.         string=stringManager.getString("httpConnector.anAddress", "192.165.23.26",12);  
  145.         System.out.println(string);  
  146.   
  147.     }  
  148.   
  149. }  
posted on 2012-09-05 00:15  刺猬的温驯  阅读(1292)  评论(0编辑  收藏  举报