Tomcat的国际化实现


对于涉及到多语言用户使用的应用,国际化是一条必经之路。Tomcat也不例外,做为一款成熟且成功的开源软件,其用户量巨大,受到全球各国的工程师喜爱。

我们在阅读其源码时,一定见到过类似下面这样的内容:

throw new IllegalArgumentException(sm.getString("coyoteConnector.parseBodyMethodNoTrace"));

其中这句sm.getString("coyoteConnector.parseBodyMethodNoTrace")里的sm,就是实现国际化的核心StringManager。 在许多类中,我们都会发现这样的字段声明:

/**
     * The string manager for this package.
     */
    protected static final StringManager sm = StringManager.getManager(Connector.class);

此时,会得到一个当前Locale对应的StringManager。注意这里保证每个包只对应一个manager。单例的实现可以参考前面的文章:

来看看你貌似熟悉的单例模式

public static final synchronized StringManager getManager(
            String packageName, Locale locale)
{
 
        Map<Locale,StringManager> map = managers.get(packageName);
        if (map == null) {
            map = new LinkedHashMap<Locale,StringManager>(LOCALE_CACHE_SIZE, 1, true);
            managers.put(packageName, map);
        }
 
        StringManager mgr = map.get(locale);
        if (mgr == null) {
            mgr = new StringManager(packageName, locale);
            map.put(locale, mgr);
        }
        return mgr;
    }

资源文件的载入是使用ResourceBundle实现的,文件是对应的packageName+LocalStrings

private StringManager(String packageName, Locale locale) {
        String bundleName = packageName + ".LocalStrings";
        ResourceBundle bnd = null;
        try {
            bnd = ResourceBundle.getBundle(bundleName, locale);
        } catch (MissingResourceException ex) {
        }
        bundle = bnd;
        if (bundle != null) {
            Locale bundleLocale = bundle.getLocale();
            if (bundleLocale.equals(Locale.ROOT)) {
                this.locale = Locale.ENGLISH;
            } else {
                this.locale = bundleLocale;
            }
        } else {
            this.locale = null;
        }
    }

这块有两个可以关注的点:

  • ResourceBundle

  • MessageFormat

其中ResourceBundle会根据指定的Locale加载对应的资源文件信息,我们一般资源文件都是xxx_fr.properties/xxx_es.properties这种形式,bundle的locale会自动匹配。


MessageFormat则会自动替换信息中的占位符,例如资源文件中有类似这样的内容:

Could not contact {0}:{1}. Tomcat may not be running.

其中{0}:{1}就是占位符,在实际使用时,会被真实的值替换。而背后的实现,正是MessageFormat.使用时,就直接传入实际值即可,如下:

 log.error(sm.getString("catalina.stopServer.connectException",
                                       s.getAddress(),
                                       String.valueOf(s.getPort())));`

在需要信息提示时,调用方法getString来获取,注意catch块中的注释,比较有意思。

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

以上,即为Tomcat国际化的实现方式,对于我们的应用开发,可以用来参考。

你可能喜欢

数据源连接池的原理及Tomcat中的应用

详解集群内Session高可用的实现原理

Java并发编程相关概念及注意事项

线程池的原理

修改JSP文件实时生效的秘密

扫描或长按下方二维码,共同成长!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值