zoukankan      html  css  js  c++  java
  • Tomcat StringManager阅读学习 我们到底能走多远系列(10)

    我们到底能走多远系列(10)

    扯淡:空闲时间不多,扯淡时间久更少了。

    主题:

     先了解下两个所谓的知识点:ResourceBundle 和 MessageFormat

    在项目里用的得心应手的properites文件,大多要用到这两个类吧。

    java.util.ResourceBundle
    java.text.MessageFormat

    1,ResourceBundle解析资源文件分两步:1加载资源文件,2获取资源文件中的信息

    // 加载资源文件
    ResourceBundle resource = ResourceBundle.getBundle("messages");
    // 获取资源文件中的信息
    String driverName = resource.getString("database.driver");

    ResourceBundle支持多国语言:先把文件名取成类似这样myres_zh_CN.properties

    然后:

    Locale locale1 = new Locale("zh", "CN");
    ResourceBundle resb1 = ResourceBundle.getBundle("myres", locale1);
    resb1.getString("aaa");

    2,MessageFormat用来格式化一个消息(字符串嘛)

    直接网上类似代码:

    String pig = "{0}{1}{2}{3}{4}{5}{6}{7}{8}{9}{10}{11}{12}{13}{14}{15}{16}";  
    Object[] array = new Object[]{"A","B","C","D","E","F","G","H","I","J","K","L","M","N","O","P","Q"};  
    String value = MessageFormat.format(pig, array);  
    System.out.println(value);  //最终结果是:ABCDEFGHIJKLMNOPQ

    3,结合在一起就可以实现,将properites文件解析出想要的消息体,然后格式化后给上一层方法用。

    myResources.properties:

    database.driver=com.mysql.jdbc.Drvier
    database.url=jdbc:mysql://localhost:3306:test
    database.user={0}
    database.pass={0}
    

    例:

    public class ResourceBundleTest {
        public static void main(String[] args) {
            // 指明包路径和文件名即可
            ResourceBundle resource = ResourceBundle.getBundle("code.stu.ResourceBundle.myResources");
            String driverName = resource.getString("database.driver");
            String url = resource.getString("database.url");
            Object[] array1 = new Object[]{"root"};
            Object[] array2 = new Object[]{"test"};
            // 取得字符串,直接格式化
            String user = MessageFormat.format(resource.getString("database.user"), new Object[]{"root"});
            String pass = MessageFormat.format(resource.getString("database.pass"), new Object[]{"test"});
    
            System.out.println(driverName + url + user + pass);//结果:com.mysql.jdbc.Drvierjdbc:mysql://localhost:3306:testroottest
        }
    }


    StringManager

    在tomcat里,把错误日志信息的字符串写在properites文件里,如此一来,打印日志的事情就可以通过上面的两个类来解决了。

    StringManager是管理打印日志的类,Tomcat的设计是,对每一个包提供自己的properites文件,也就是说,每一个包的日志信息只需要去各自包的properites文件里去找就可以了,然后Tomcat为每一个包提供一个StringManager实例,相当于一个包一个单例的效果(值得学习下)。各自的StringManager实例来管理各自包下的日志打印。

    源码如下:

    package org.apache.catalina.util;
    
    import java.text.MessageFormat;
    import java.util.Hashtable;
    import java.util.Locale;
    import java.util.MissingResourceException;
    import java.util.ResourceBundle;
    import java.net.URLClassLoader;
    
    public class StringManager {
    
        // ResourceBundle用于读取properties文件
        private ResourceBundle bundle;
        
        private static org.apache.juli.logging.Log log=
            org.apache.juli.logging.LogFactory.getLog( StringManager.class );
        
        // 私有的构造方法能够保证外界无法实例化自己,这也是单例实现的关键步骤
        private StringManager(String packageName) {
            // properties文件所在的package+“.LocalStrings”
            // 所有tomcat的日志使用的properties文件都依照这个形式来命名的
            String bundleName = packageName + ".LocalStrings";
            try {
                // 根据bundleName取得解析资源文件的实例
                bundle = ResourceBundle.getBundle(bundleName);
                return;
            } catch( MissingResourceException ex ) {// 好吧,异常就先不管了。
                // Try from the current loader ( that's the case for trusted apps )
                ClassLoader cl=Thread.currentThread().getContextClassLoader();
                if( cl != null ) {
                    try {
                        bundle=ResourceBundle.getBundle(bundleName, Locale.getDefault(), cl);
                        return;
                    } catch(MissingResourceException ex2) {
                    }
                }
                if( cl==null )
                    cl=this.getClass().getClassLoader();
    
                if (log.isDebugEnabled())
                    log.debug("Can't find resource " + bundleName +
                        " " + cl);
                if( cl instanceof URLClassLoader ) {
                    if (log.isDebugEnabled()) 
                        log.debug( ((URLClassLoader)cl).getURLs());
                }
            }
        }
    
        /**
         * Get a string from the underlying resource bundle.
         *
         * @param key The resource name
         */
        public String getString(String key) {
            return MessageFormat.format(getStringInternal(key), (Object [])null);
        }
    
    
        protected String getStringInternal(String key) {
            // key 还是要保证不是null
            if (key == null) {
                String msg = "key is null";
    
                throw new NullPointerException(msg);
            }
            // 返回string
            String str = null;
    
            if( bundle==null )
                return key;
            try {
                // 资源文件里去查有没有对应的内容
                str = bundle.getString(key);
            } catch (MissingResourceException mre) {
                str = "Cannot find message associated with key '" + key + "'";
            }
    
            return str;
        }
        public String getString(String key, Object[] args) {
            String iString = null;
            String value = getStringInternal(key);
    
            // this check for the runtime exception is some pre 1.1.6
            // VM's don't do an automatic toString() on the passed in
            // objects and barf out
    
            try {
                // ensure the arguments are not null so pre 1.2 VM's don't barf
                Object nonNullArgs[] = args;
                for (int i=0; i<args.length; i++) {
                    if (args[i] == null) {
                        if (nonNullArgs==args) nonNullArgs=(Object[])args.clone();
                        nonNullArgs[i] = "null";
                    }
                }
                // 格式化,就是把一些变化的参数插入到value这个string中去,格式化成一个新的最终的string
                iString = MessageFormat.format(value, nonNullArgs);
            } catch (IllegalArgumentException iae) {
                StringBuffer buf = new StringBuffer();
                buf.append(value);
                for (int i = 0; i < args.length; i++) {
                    buf.append(" arg[" + i + "]=" + args[i]);
                }
                iString = buf.toString();
            }
            return iString;
        }
    
        // 下面四个getString方法,最终都需要调用getString(String key, Object[] args)
        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);
        }
        
        // Hashtable维护整个tomcat的StringManager
        private static Hashtable managers = new Hashtable();
    
        // 保证一个包一个StringManager,私有化构造函数+Hashtable维护实现(值得学习)
        // 从而避免大量的StringManager实例化和销毁的操作,毕竟写日志属于比较频繁的操作。
        public synchronized static StringManager getManager(String packageName) {
            // 用一个Hashtable来管理控制,保证每个包提供一个StringManager
            StringManager mgr = (StringManager)managers.get(packageName);
            // 属于这个包的Manager有了吗
            if (mgr == null) {
                mgr = new StringManager(packageName);
                // 实例化好后,把它放进Hashtable里去,下次就不用实例化了
                managers.put(packageName, mgr);
            }
            return mgr;
        }
    }


    总结:记得以前连单例是神马都不知道,现如今可以按包给单例,我想还会有更多变化可以学习。没有做不到,只有想不到,哈哈。

    让我们继续前行

    ----------------------------------------------------------------------

    努力不一定成功,但不努力肯定不会成功。
    共勉

  • 相关阅读:
    关押罪犯
    文化之旅
    [USACO11OPEN]玉米田迷宫Corn Maze
    排队布局
    最短路计数
    【模板】单源最短路径(标准版)
    最短路径问题
    无向图最小环
    localStorage的使用
    移动端如何引入日期插件
  • 原文地址:https://www.cnblogs.com/killbug/p/2728551.html
Copyright © 2011-2022 走看看