像Tomcat这样的使用如此广泛的软件,对日志的国际化处理显得格外重要。日志作为一个特殊的切面,贯穿整个系统的各个阶段,所以设计时格外小心.
下面介绍Tomcat中日志处理方案:
public class StringManager {
private ResourceBundle bundle;
private static Log log = LogFactory.getLog(StringManager.class);
private static Hashtable managers = new Hashtable();
public synchronized static StringManager getManager(String packageName) {
StringManager mgr = (StringManager) managers.get(packageName);
if (mgr == null) {
mgr = new StringManager(packageName);
managers.put(packageName, mgr);
}
return mgr;
}
private StringManager(String packageName) {
String bundleName = packageName + ".LocalString";
try {
bundle = ResourceBundle.getBundle(bundleName);
return;
} catch (MissingResourceException ex) {
ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
if (classLoader != null) {
try {
bundle = ResourceBundle.getBundle(bundleName, Locale.getDefault(), classLoader);
return;
} catch (MissingResourceException ex2) {
}
}
if (classLoader == null) {
classLoader = this.getClass().getClassLoader();
}
if (log.isDebugEnabled()) {
log.debug("Can't find resource " + bundleName + " " + classLoader);
}
if (classLoader instanceof URLClassLoader) {
if (log.isDebugEnabled()) {
log.debug(((URLClassLoader) classLoader).getURLs());
}
}
}
}
public String getString(String key) {
return MessageFormat.format(getStringInternal(key), (Object[]) null);
}
protected String getStringInternal(String key) {
if (key == null) {
String msg = "key is null";
throw new NullPointerException(msg);
}
String str;
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;
String value = getStringInternal(key);
try {
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";
}
}
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;
}
}
ResourceBundle 是java.util
包下面一个解析资源的类;
ResourceBundle 解析资源文件一般分两步:
[1] 加载资源文件;
[2] 获取资源文件中的信息。
// 加载资源文件
ResourceBundle resource = ResourceBundle.getBundle("messages");
// 获取资源文件中的信息
String driverName = resource.getString("database.driver");
Tomcat 国际化的关键就是依靠这个类的,通过运行时动态设置地区语言完成日志配置的自动化获取。
Locale locale1 = new Locale("zh", "CN");
ResourceBundle resb1 = ResourceBundle.getBundle("myres", locale1);
上面的代码将会加载myres_zh_CN.properties
文件内容。
MessageFormat 用来格式化一个消息,一般就是用来热替换原始 string中的{}
常见用法如下:
String params = "{0}-{1}";
Object[] array = new Object[]{"ggr","男"};
String value = MessageFormat.format(userInfo, params);
总结:Tomcat 通过ResourceBundle + MessageFormat 解决了国际化的问题,同时通过给每一个包建立一个独立日志文件来避免所有的日志往同一个文件写带来的写的性能问题,将log模块化更加有利于开发和测试以及运维人员对日志文件的管理和维护。