Tomcat的信息国际化之路

来源:互联网 发布:mac子弹头专柜价格 编辑:程序博客网 时间:2024/05/17 09:14

我们都知道Tomcat是一个很流行的轻量级应用容器,正因为他的流行,他有各种各样的说各种语言的用户群体,那么他是怎么解决信息国际化呢?

先看一下JDK是怎么处理信息国际化:

创建几个资源文件:

msg.properties

name=dusk
对应的中文文件message_zh.properties

name=dushangkui

以及中国地区的中文文件message_zh_cn.properties

name=\u675c\u5c1a\u594e

创建场景类:

package dusk.file.local;import org.junit.Test;import java.util.Locale;import java.util.ResourceBundle;/** * Created by dushangkui on 2017/5/10. */public class TestLocal {    @Test    public void test(){        Locale locale1 = new Locale("");        Locale locale2 = new Locale("zh");        Locale locale3 = new Locale("zh","cn");        ResourceBundle bnd1 = ResourceBundle.getBundle(TestLocal.class.getPackage().getName()+".message", locale1);        ResourceBundle bnd2 = ResourceBundle.getBundle(TestLocal.class.getPackage().getName()+".message", locale2);        ResourceBundle bnd3 = ResourceBundle.getBundle(TestLocal.class.getPackage().getName()+".message", locale3);        System.out.println(bnd1.getString("name"));        System.out.println(bnd2.getString("name"));        System.out.println(bnd3.getString("name"));    }}

运行结果:


我们可以看到根据不同的Locale信息,我们获取到了不同的适合结果。

注: java.util.Locale是本地化辅助类,用于描述特定的地理、政治和文化地区。

我们的项目结构如下:


现在回到正题,Tomcat是怎么做信息国际化呢?

是通过类org.apache.naming.StringManager完成的,它里面封装了对ResourceBundle的处理,因为ResourceBundle需要两个参数,文件类路径以及Locale信息,所以Tomcat的StringManager也是基于包完成的。我们可以看一个实际使用例子:



查看源码,我们很容易知道他是一个单例类。其中一个很重要的方法是

 public String getString(String key)
根据一个key获取对应的信息。当然了还有一个可以带参数格式化信息的重载方法:

public String getString(final String key, final Object... args)


创建StringManager的关键代码:

 /**     * Creates a new StringManager for a given package. This is a     * private method and all access to it is arbitrated by the     * static getManager method call so that only one StringManager     * per package will be created.     *     * @param packageName Name of package to create StringManager for.     */    private StringManager(String packageName, Locale locale) {        String bundleName = packageName + ".LocalStrings";        ResourceBundle bnd = null;        try {            bnd = ResourceBundle.getBundle(bundleName, locale);        } catch( MissingResourceException ex ) {            // Try from the current loader (that's the case for trusted apps)            // Should only be required if using a TC5 style classloader structure            // where common != shared != server            ClassLoader cl = Thread.currentThread().getContextClassLoader();            if( cl != null ) {                try {                    bnd = ResourceBundle.getBundle(bundleName, locale, cl);                } catch(MissingResourceException ex2) {                    // Ignore                }            }        }        bundle = bnd;        // Get the actual locale, which may be different from the requested one        if (bundle != null) {            Locale bundleLocale = bundle.getLocale();            if (bundleLocale.equals(Locale.ROOT)) {                this.locale = Locale.ENGLISH;            } else {                this.locale = bundleLocale;            }        } else {            this.locale = null;        }    }

getString的关键代码

    /**        Get a string from the underlying resource bundle or return        null if the String is not found.        @param key to desired resource String        @return resource String matching <i>key</i> from underlying                bundle or null if not found.        @throws IllegalArgumentException if <i>key</i> is null.     */    public String getString(String key) {        if(key == null){            String msg = "key may not have a null value";            throw new IllegalArgumentException(msg);        }        String str = null;        try {            // Avoid NPE if bundle is null and treat it like an MRE            if (bundle != null) {                str = bundle.getString(key);            }        } catch(MissingResourceException mre) {            //bad: shouldn't mask an exception the following way:            //   str = "[cannot find message associated with key '" + key +            //         "' due to " + mre + "]";            //     because it hides the fact that the String was missing            //     from the calling code.            //good: could just throw the exception (or wrap it in another)            //      but that would probably cause much havoc on existing            //      code.            //better: consistent with container pattern to            //      simply return null.  Calling code can then do            //      a null check.            str = null;        }        return str;    }

可以看出获取国际化信息的时候透传给了ResourceBundle。





1 0
原创粉丝点击