zoukankan      html  css  js  c++  java
  • StringManager与单例模式

    在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. }  
  • 相关阅读:
    GUI基础学习
    常用类string的用法
    类。对象和包--补上周
    类.对象和包
    调用函数的注意事项
    函数的简单运用
    一维数组基础
    java中scanner类的用法
    数据库——DQL(语句查询)
    数据库——JDBC
  • 原文地址:https://www.cnblogs.com/chenying99/p/2671204.html
Copyright © 2011-2022 走看看