在webwork2.2.6版本中,不管是用ServletDispatcher还是FilterDispatcher充当请求转发器(可在web.xml中配置),都会调用到相关Servlet的init或Filter的init方法。
在init方法中,DispatcherUtils.initialize(getServletContext())的调用完成了配置文件的读取、ObjectFactory的设置(也是根据配置文件)。类Configuration充当了读取配置文件的功能。其子类包括:
webwork提供了默认资源文件类型、property资源文件类型,还有DelegatingConfiguration资源文件类型 ,你也可以实现自己的XMLConnfiguration。
查看Configuration类代码,我们可以看到非静态方法,包括isSetImpl(String name)直接返回false,setImpl(String name, Object value)直接抛出异常,这是一种变态的abstract类设计,在需要使用该类的静态方法,却又不愿意调用者实例化该类并调用非静态方法时候,用这种变通的做法也是不错的选择。(因为我们不能同时让static和abstract修饰一个类)。
另外,该做法实现了多态,在这种多态中,子类可以被任意更换,确只保证只有一个之类实例存在。实现方法是在Configuration中建立静态变量static Configuration configurationImpl;调用端可以通过实例化不同的子类赋予configurationImpl。最后通过Configuration.getConfiguration() 获取唯一的实例。
这样的设计在webwork其他地方也经常可见。如ActionProxyFactory及其子类,但是不同的是ActionProxyFactory是absctract的,因为ActionProxyFactory没有设计有静态方法。
这种设计在策略互换且只允许单个策略的情况下相当有用,今天看了这段代码,且做一个笔记。
代码如下:::
public class Configuration { static Configuration configurationImpl; static Configuration defaultImpl; static Locale locale; // Cached locale private static final Log LOG = LogFactory.getLog(Configuration.class); /** * Sets the current configuration implementation. Can only be called once. * * @param config a Configuration implementation * @throws IllegalStateException if an error occurs when setting the configuration implementation. */ public static void setConfiguration(Configuration config) throws IllegalStateException { configurationImpl = config; locale = null; // Reset cached locale } /** * Gets the current configuration implementation. * * @return the current configuration implementation. */ public static Configuration getConfiguration() { return (configurationImpl == null) ? getDefaultConfiguration() : configurationImpl; } /** * Returns the WebWork2 locale. Keys off the property webwork.locale which should be set * as the Java {@link java.util.Locale#toString() toString()} representation of a Locale object (i.e., * "en", "de_DE", "_GB", "en_US_WIN", "de__POSIX", "fr_MAC", etc).*
* If no locale is specified then the default VM locale is used ({@link java.util.Locale#getDefault()}). * * @return the WebWork2 locale if specified or the VM default locale. */ public static Locale getLocale() { if (locale == null) { try { StringTokenizer localeTokens = new StringTokenizer(getString(WebWorkConstants.WEBWORK_LOCALE), "_"); String lang = null; String country = null; if (localeTokens.hasMoreTokens()) { lang = localeTokens.nextToken(); } if (localeTokens.hasMoreTokens()) { country = localeTokens.nextToken(); } locale = new Locale(lang, country); } catch (Throwable t) { // Default LOG.warn("Setting locale to the default locale"); locale = Locale.getDefault(); } } return locale; } /** * Determines whether or not a value has been set. Useful for testing for the existance of parameter without * throwing an IllegalArgumentException. * * @param name the name of the property to test. * @return true if the property exists and has a value, false otherwise. */ public static boolean isSet(String name) { return getConfiguration().isSetImpl(name); } /** * Returns a property as a String. This will throw an IllegalArgumentException if an error occurs * while retrieveing the property or if the property doesn't exist. * * @param name the name of the property to get. * @return the property as a String * @throws IllegalArgumentException if an error occurs retrieveing the property or the property does not exist. */ public static String getString(String name) throws IllegalArgumentException { String val = get(name).toString(); return val; } /** * Returns a property as an Object. This will throw an IllegalArgumentException if an error occurs * while retrieveing the property or if the property doesn't exist. * * @param name the name of the property to get. * @return the property as an Object. * @throws IllegalArgumentException if an error occurs retrieveing the property or the property does not exist. */ public static Object get(String name) throws IllegalArgumentException { Object val = getConfiguration().getImpl(name); return val; } /** * Returns an Iterator of all properties names. * * @return an Iterator of all properties names. */ public static Iterator list() { return getConfiguration().listImpl(); } /** * Implementation of the {@link #isSet(String)} method. * * @see #isSet(String) */ public boolean isSetImpl(String name) { // this is dumb.. maybe it should just throw an unsupported op like the rest of the *Impl // methods in this class. return false; } /** * Sets a property. Throws an exception if an error occurs when setting the property or if the * Configuration implementation does not support setting properties. * * @param name the name of the property to set. * @param value the property to set. * @throws IllegalArgumentException if an error occurs when setting the property. * @throws UnsupportedOperationException if the config implementation does not support setting properties. */ public static void set(String name, Object value) throws IllegalArgumentException, UnsupportedOperationException { getConfiguration().setImpl(name, value); } /** * Implementation of the {@link #set(String, Object)} method. * * @see #set(String, Object) */ public void setImpl(String name, Object value) throws IllegalArgumentException, UnsupportedOperationException { throw new UnsupportedOperationException("This configuration does not support updating a setting"); } /** * Implementation of the {@link #get(String)} method. * * @see #get(String) */ public Object getImpl(String aName) throws IllegalArgumentException { return null; } /** * Implementation of the {@link #list()} method. * * @see #list() */ public Iterator listImpl() { throw new UnsupportedOperationException("This configuration does not support listing the settings"); } private static Configuration getDefaultConfiguration() { if (defaultImpl == null) { // Create bootstrap implementation defaultImpl = new DefaultConfiguration(); // Create default implementation try { String className = getString(WebWorkConstants.WEBWORK_CONFIGURATION); if (!className.equals(defaultImpl.getClass().getName())) { try { // singleton instances shouldn't be built accessing request or session-specific context data defaultImpl = (Configuration) ObjectFactory.getObjectFactory().buildBean(Thread.currentThread().getContextClassLoader().loadClass(className), null); } catch (Exception e) { LOG.error("Could not instantiate configuration", e); } } } catch (IllegalArgumentException ex) { // ignore } } return defaultImpl; } public static void reset() { defaultImpl = null; configurationImpl = null; } }