Webwork【04】Configuration 详解
Webwork做为经典的Web MVC 框架,个人觉得源码中配置文件这部分代码的实现十分考究。
支持自定义自己的配置文件、自定义配置文件读取类、自定义国际化支持。
可以作为参考,单独引入到其他项目中,下面是Configuration相关类的继承关系:

1. Configuration
- Configuration 作为 webwork 配置文件的核心类,起到了配置信息读取的门户,默认实现类中间引入了代理类 DelegatingConfiguration 与底层的具体实现读取的 PropertiesConfiguration 完全解耦。在项目中使用时,只需要引入 Configuration 类,如下代码即可获取配置信息;
Configuration.getString("webwork.locale")
- getString 方法会调用 Configuration 自身的get 方法,get 方法中调用 getConfiguration 方法:
public static String getString(String name) throws IllegalArgumentException {
String val = get(name).toString();
return val;
}
public static Object get(String name) throws IllegalArgumentException {
Object val = getConfiguration().getImpl(name);
return val;
}
public static Configuration getConfiguration() {
return configurationImpl == null ? getDefaultConfiguration() : configurationImpl;
}
- Configuration 中定义的两个静态变量defaultImpl 和configurationImpl,还有 一个setConfiguration方法用来设置configurationImpl;
- defaultImpl 是 WebWork 的默认实现类实例的引用,在每一次读取配置文件时,都会去判断是否在 webwork.properties 是否配置了 webwork.configuration 参数(其实框架是无法实现热读配置文件的,下面会说到,每次判断只是确定读取配置信息,使用的框架默认类还是用户自定义类);
- 如果设置了在调用 getDefaultConfiguration() 获得自定义读取类引用 configurationImpl,否则返回 WebWork 自己的 Configuration 实现。
(这里要说一下,随意变动上线系统的配置文件,你会悲剧的,修改前记得问清楚)
private static Configuration getDefaultConfiguration() {
if (defaultImpl == null) {
defaultImpl = new DefaultConfiguration();
try {
String className = getString("webwork.configuration");
if (!className.equals(defaultImpl.getClass().getName())) {
try {
defaultImpl = (Configuration) ObjectFactory.getObjectFactory().buildBean(Thread.currentThread().getContextClassLoader().loadClass(className));
} catch (Exception e) {
log.error("Could not instantiate configuration", e);
}
}
return defaultImpl;
} catch (IllegalArgumentException localIllegalArgumentException) {
}
}
return defaultImpl;
}
- 第一次调用 getDefaultConfiguration() 方法时,默认实现 defaultImpl 是空,则进入创建一 个 WebWork 自己的实现 DefaultConfiguration 的实例,并通过这个实例读取 WebWork 配置信息。
- 上面代码第5行有个特殊的地方,和下面的 DelegatingConfiguration中的很相似,下面一起说。
2. DefaultConfiguration
public DefaultConfiguration() {
ArrayList list = new ArrayList();
try {
list.add(new PropertiesConfiguration("webwork"));
} catch (Exception e) {
this.log.warn("Could not find webwork.properties");
}
try {
list.add(new PropertiesConfiguration("com/opensymphony/webwork/default"));
} catch (Exception e) {
this.log.error("Could not find com/opensymphony/webwork/default.properties", e);
}
Configuration[] configList = new Configuration[list.size()];
this.config = new DelegatingConfiguration((Configuration[]) list.toArray(configList));
try {
StringTokenizer configFiles = new StringTokenizer((String) this.config.getImpl("webwork.custom.properties"), ",");
while (configFiles.hasMoreTokens()) {
String name = configFiles.nextToken();
try {
list.add(new PropertiesConfiguration(name));
} catch (Exception e) {
this.log.error("Could not find " + name + ".properties. Skipping");
}
}
configList = new Configuration[list.size()];
this.config = new DelegatingConfiguration((Configuration[]) list.toArray(configList));
} catch (IllegalArgumentException localIllegalArgumentException) {
}
try {
StringTokenizer bundleFiles = new StringTokenizer((String) this.config.getImpl("webwork.custom.i18n.resources"), ",");
while (bundleFiles.hasMoreTokens()) {
String name = bundleFiles.nextToken();
try {
this.log.info("Loading global messages from " + name);
LocalizedTextUtil.addDefaultResourceBundle(name);
} catch (Exception e) {
this.log.error("Could not find " + name + ".properties. Skipping");
}
}
} catch (IllegalArgumentException localIllegalArgumentException1) {
}
}
DefaultConfiguration构造函数
- DefaultConfiguration 并没有直接取读取properties文件,而是通过 PropertiesConfiguration 来实现properties文件的读取;
- PropertiesConfiguration 也同样是 Configuration 的子类,通过java.util.Properties 来解析properties文件,并 赋予自身Properties 实例settings,并覆盖了父类的setImpl、getImpl、isSetImpl、 listImpl 四个方法;
- DefaultConfiguration 通 过 PropertiesConfiguration 首 先 加 载 的 是 webwork.properties,之后又加载了default.properties;
(这里需要说一下,default.properties 是webwork 框架自身的配置文件,封装在 jar 中,假如你在项目的 web.properties 中定义了与 default.properties 相同的参数,看上面程序配置文件的加载顺序,框架先加载你的配置文件,然后加载默认配置文件,你会发现你的参数是不会起作用的,如果你想让你的参数覆盖框架中的,这里你需要自定义配置文件,并且在 项目 webwork.properties 中配置 webwork.custom.properties 参数)
- 将 PropertiesConfiguration 实例放入List中,然后创建一个和 List一样大的Configuration[]数组,并把List 转型为 Configuration[]赋予 实例化 DelegatingConfiguration;
- 加载完两个properties 文件,并创建了DelegatingConfiguration 实例之后, DefaultConfiguration开始在这两个属性文件中查找 webwork.custom.properties,文件名之间用“,”隔开。找到配置后,分割文件名并分别创建PropertiesConfiguration 实例,加入List,加载完所有配置文 件后重新创建DelegatingConfiguration 实例。
- 加载完所有的WebWork 属性文件后, 查找属性文件中指定的国际化资源文件(文件名同样用“,”隔开),如果有,则加载到 LocalizedTextUtil 中,供以后使用。
(毕竟是好多年前编写的源码,这里面的 StringTokenizer 出于兼容性的原因已经被遗留(虽然在新代码中并不鼓励使用它)。API 中建议所有寻求此功能的人使用 String 的 split 方法或 java.util.regex 包)
3. DelegatingConfiguration
- DelegatingConfiguration 也同样是 Configuration 的子类,内部保存了一个 Configuration[]数组configList,并覆 盖了父类的setImpl、getImpl、isSetImpl、listImpl 四个方法,实现对configList 的操作;
- 如果用户没有指定自己的 Configuration 实现,则 Configuration.getString 最终调用的是 DelegatingConfiguration 的 getImpl;
- 在 DelegatingConfiguration 的setImpl 方法实现中,有一个特别的地方,其实也就是上面 Configuration提到的f,底层的实现:
public void setImpl(String name, Object value) throws IllegalArgumentException, UnsupportedOperationException {
IllegalArgumentException e = null;
for (int i = 0; i < this.configList.length; i++) {
try {
this.configList[i].getImpl(name);
this.configList[i].setImpl(name, value);
return;
} catch (IllegalArgumentException ex) {
e = ex;
}
}
throw e;
}
WebWork不支持动态的增加属性配置,但允许修改已配置的属性, configList[i].getImpl(name); 调用的是 PropertiesConfiguration 的 getImpl 方法,实现如下:
public Object getImpl(String aName) throws IllegalArgumentException {
Object setting = this.settings.get(aName);
if (setting == null) {
throw new IllegalArgumentException("No such setting:" + aName);
}
return setting;
}
PropertiesConfiguration 会在settings 里去找name,如果找到就返回配置信息,在 DelegatingConfiguration 的setImpl 方法中通过configList[i].setImpl(name, value)修改该属性的配置,否则抛IllegalArgumentException 异常,该异常在 DelegatingConfiguration 的 getImpl 方法中截 获 ,继续往被调用函数抛。 此时则不会执行 configList[i].setImpl(name, value);从而保证了只有配置过了的属性可以被修改,在服务运行的过程中不会有新增的属性,所有的属性都由 Web 服务第一次启动的时候加载。
4. webwork[三][四]小结
以上分析我们可以看见,Web 服务启动的时候,ServletDispatcher 通过 DefaultConfiguration 先 加 载 webwork.properties 和 default.properties , 并 查 找 webwork.properties中webwork.custom.properties 配置的其他属性文件加载。加载完毕 后再通过属性中配置的 webwork.custom.i18n.resources 加载国际化资源文件供以后 使用。之后再查找 webwork.configuration 属性看是否用户指定了自己的 Configuration 实现,如果有就用用户自己的Configuration 实现,否则返回WebWork 自己的实现(DelegatingConfiguration)。大部分情况下,使用 WebWork 自己的实现 已经足够,用户不需要自己去实现一个 Configuration,除非你想加载XML等格式的配 置文件。
Webwork【04】Configuration 详解的更多相关文章
- Webwork 学习之路【04】Configuration 详解
Webwork做为经典的Web MVC 框架,个人觉得源码中配置文件这部分代码的实现十分考究. 支持自定义自己的配置文件.自定义配置文件读取类.自定义国际化支持. 可以作为参考,单独引入到其他项目中, ...
- mongodb学习04 操作详解(2)
查找文档 筛选查找 db.collection.find(); 返回一个集合中文档的子集,子集的 范围从 0 个文档到整个集合; db.collection.findOne(); 返回筛选的一个文档; ...
- 【WebApi系列】详解WebApi如何传递参数
WebApi系列文章 [01]浅谈HTTP在WebApi开发中的运用 [02]聊聊WebApi体系结构 [03]详解WebApi参数的传递 [04]详解WebApi测试和PostMan [05]浅谈W ...
- Mybatis详解(二) sqlsession的创建过程
我们处于的位置 我们要清楚现在的情况. 现在我们已经调用了SqlSessionFactoryBuilder的build方法生成了SqlSessionFactory 对象. 但是如标题所说,要想生成sq ...
- Ubuntu14.04下Mongodb(离线安装方式|非apt-get)安装部署步骤(图文详解)(博主推荐)
不多说,直接上干货! 说在前面的话 首先,查看下你的操作系统的版本. root@zhouls-virtual-machine:~# cat /etc/issue Ubuntu LTS \n \l r ...
- Ubuntu16.04下Mongodb(离线安装方式|非apt-get)安装部署步骤(图文详解)(博主推荐)
不多说,直接上干货! 说在前面的话 首先,查看下你的操作系统的版本. root@zhouls-virtual-machine:~# cat /etc/issue Ubuntu LTS \n \l r ...
- Ubuntu14.04下完美安装cloudermanage多种方式(图文详解)(博主推荐)
说在前面的话 我的机器是总共4台,分别为ubuntucmbigdata1.ubuntucmbigdata2.ubuntucmbigdata3和ubuntucmbigdata4. ClouderaMan ...
- 基于CentOS6.5或Ubuntu14.04下Suricata里搭配安装 ELK (elasticsearch, logstash, kibana)(图文详解)
前期博客 基于CentOS6.5下Suricata(一款高性能的网络IDS.IPS和网络安全监控引擎)的搭建(图文详解)(博主推荐) 基于Ubuntu14.04下Suricata(一款高性能的网络ID ...
- Ubuntu16.04下沙盒数据导入到 Neo4j 数据库(图文详解)
不多说,直接上干货! 参考博客 http://blog.csdn.net/u012318074/article/details/72793914 (表示感谢) 前期博客 Neo4j沙盒实验申请过 ...
随机推荐
- Java并发编程的艺术(八)——闭锁、同步屏障、信号量详解
1. 闭锁:CountDownLatch 1.1 使用场景 若有多条线程,其中一条线程需要等到其他所有线程准备完所需的资源后才能运行,这样的情况可以使用闭锁. 1.2 代码实现 // 初始化闭锁,并设 ...
- 解决appcompat中各种奇葩的错误
一.依赖/脱离appcompat 在新版本中Google跟新了一个依赖包,这个包包含了v4和v7的东西(v7是要依赖v4这个包的,所以用到v7时必须用一起的v4),只要你的编译版本compile wi ...
- 将win7电脑无线网变身WiFi热点,让手机、笔记本共享上网
1.以管理员身份运行命令提示符:快捷键win+R→输入cmd→回车 2.启用并设定虚拟WiFi网卡:运行命令:netsh wlan set hostednetwork mode=allow ssid= ...
- Linux 批量查找替换方法(VIM和sed)
版权声明:欢迎与我交流讨论,若要转载请注明出处~ https://blog.csdn.net/sinat_36053757/article/details/70946263 1.VIM命令 当前行进行 ...
- springMVC4(14)各类视图输出实例分析
1. 模板视图 FreeMarkerViewResolver . VolocityViewResolver 这两个视图解析器都是 UrlBasedViewResolver 的子类. FreeMarke ...
- 1、Python简史
Python简史 什么是Python 一种解释型的.面向对象的.带有动态语义的高级程序设计语言 Python编程 是一种使你在编程时能够保持自己风格的程序设计语言,你不用费什么劲就可以实现你想要的功能 ...
- CSS只是进化的一部分
Bert Bos是一位计算机科学家,他也是CSS的创始人之一.在CSS的发展过程中,Bos是最早与Håkon Wium Lie(CSS之父)合作的人之一.在1996年,他加入了World Wide W ...
- SQLServer 数据库镜像+复制切换方案
目标: 主机做了Mirror和Replication,当主机出现问题时,Replication和Mirror实现自动的故障转移(Mirror 和Replication都切换到备机,而当主机 重新启动后 ...
- 关于如何使用javascript监听滚动条滚动事件
在网页中,通常有一个通往网页顶部的锚点,现在我们就来实现它 Html代码: <a id="scrollup" href="#top" style=&quo ...
- Laravel validate 500异常 添加手机验证,中文验证与Validator验证的“半个”生命周期
今天来讲一下,Lumen的Validator函数 1 2 3 4 5 6 7 8 9 10 11 use Validator; ... Class .. { public function ...