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;
    }
}


總結:記得以前連單例是神馬都不知道,現如今可以按包給單例,我想還會有更多變化可以學習。沒有做不到,只有想不到,哈哈。

 

讓我們繼續前行

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

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

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM