转载

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会自动匹配。

Tomcat 的国际化实现

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文件实时生效的秘密

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

Tomcat 的国际化实现

原文  http://mp.weixin.qq.com/s?__biz=MzI3MTEwODc5Ng==&mid=2650859207&idx=1&sn=291153d543eaa77b514fe322e9e82702
正文到此结束
Loading...