struts国际化研究(二)——工厂模式
?
抽象工厂模式
? ? ? 在struts国际化研究(一)中介绍了struts的默认国际化的默认实现类,但是在国际化的过程中,大多方法使用是MessageResources类中的方法,这里就是struts国际化的核心。
?
? ? ? 抽象工厂模式定义:提供一个接口,用于创建相关或依赖的对象家族,而不需要指定具体类。
?
? ? ? MessageResources是一个抽象类(特殊的接口),其中仅有一个抽象方法public abstract String getMessage(Locale locale, String key),这个正式国际化的入口。
? ? ? PropertyMessageResources(struts默认国际化类)继承MessageResources并实现的getMessage(Locale locale, String key)方法,当然自定义的国际化类也实现该接口,从而形成国际化文件家族。
?
public String getMessage(Locale locale, String key) { if (log.isDebugEnabled()) { log.debug("getMessage(" + locale + "," + key + ")"); } // Initialize variables we will require String localeKey = localeKey(locale); String originalKey = messageKey(localeKey, key); String messageKey = null; String message = null; int underscore = 0; boolean addIt = false; // Add if not found under the original key // Loop from specific to general Locales looking for this message while (true) { // Load this Locale's messages if we have not done so yet loadLocale(localeKey); // Check if we have this key for the current locale key messageKey = messageKey(localeKey, key); synchronized (messages) { message = (String) messages.get(messageKey); if (message != null) { if (addIt) { messages.put(originalKey, message); } return (message); } } // Strip trailing modifiers to try a more general locale key addIt = true; underscore = localeKey.lastIndexOf("_"); if (underscore < 0) { break; } localeKey = localeKey.substring(0, underscore); } // Try the default locale if the current locale is different if (!defaultLocale.equals(locale)) { localeKey = localeKey(defaultLocale); messageKey = messageKey(localeKey, key); loadLocale(localeKey); synchronized (messages) { message = (String) messages.get(messageKey); if (message != null) { messages.put(originalKey, message); return (message); } } } // As a last resort, try the default Locale localeKey = ""; messageKey = messageKey(localeKey, key); loadLocale(localeKey); synchronized (messages) { message = (String) messages.get(messageKey); if (message != null) { messages.put(originalKey, message); return (message); } } // Return an appropriate error indication if (returnNull) { return (null); } else { return ("???" + messageKey(locale, key) + "???"); } }?
?
?
工厂方法模式
工厂方法模式:定义一个创建对象的接口,但由子类决定要实例化的类是哪一个。工厂方法让类把实例化推迟到子类。
?
? ? ? struts的工厂类MessageResourcesFactory,他是一个抽象类,包含一个抽象方法public abstract MessageResources createResources(String config),它的作用正如起名创建资源,怎么创建?看默认实现类。
? ? ? MessageResourcesFactory的factoryClass指定了默认实现类PropertyMessageResourcesFactory
protected static String factoryClass = "org.apache.struts.util.PropertyMessageResourcesFactory";
PropertyMessageResourcesFactory很简单,就一个方法
?
public MessageResources createResources(String config) { return new PropertyMessageResources(this, config, this.returnNull); }?
?
?
?
现在看一下struts是如何运用这个工程类创建MessageResources
struts的核心加载类是ActionServlet,他的initModuleMessageResources(ModuleConfig config)方法对国际化类进行初始化
?
protected void initModuleMessageResources(ModuleConfig config) throws ServletException { MessageResourcesConfig mrcs[] = config.findMessageResourcesConfigs(); for (int i = 0; i < mrcs.length; i++) { if ((mrcs[i].getFactory() == null) || (mrcs[i].getParameter() == null)) { continue; } if (log.isDebugEnabled()) { log.debug( "Initializing module path '" + config.getPrefix() + "' message resources from '" + mrcs[i].getParameter() + "'"); } // 读取struts-config.xml中message-resources的属性 String factory = mrcs[i].getFactory(); // 该方法将覆盖factoryClass值(factoryClass上文中提到,工厂初始化类路径) MessageResourcesFactory.setFactoryClass(factory); // 调用createResources方法了,默认使用的是PropertyMessageResourcesFactory的,如果在struts-config.xml中定义了工厂类,这里将使用用户自定义的创建方法 MessageResourcesFactory factoryObject = MessageResourcesFactory.createFactory(); factoryObject.setConfig(mrcs[i]); // 通过factory创建MessageResources后,设置基本属性,这些属性是抽象工厂创建国际化家族所需的基本属性 MessageResources resources = factoryObject.createResources(mrcs[i].getParameter()); resources.setReturnNull(mrcs[i].getNull()); resources.setEscape(mrcs[i].isEscape()); getServletContext().setAttribute( mrcs[i].getKey() + config.getPrefix(), resources); } }
? ? ? 这里还有一个实现细节需要注意PropertyMessageResourcesFactory的createResources方法在创建MessageResources的同时,将自己注入到了新创建的MesageResources中 ,MessageResources可以通过getFactory()方法轻松获取工厂类。
?
?