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 详解的更多相关文章

  1. Webwork 学习之路【03】核心类 ServletDispatcher 的初始化

    1. Webwork 与 Xwork 搭建环境需要的的jar 为:webwork-core-1.0.jar,xwork-1.0.jar,搭建webwork 需要xwork 的jar呢?原因是这样的,W ...

  2. Java学习-007-Log4J 日志记录配置文件详解及实例源代码

    此文主要讲述在初学 Java 时,常用的 Log4J 日志记录配置文件详解及实例源代码整理.希望能对初学 Java 编程的亲们有所帮助.若有不足之处,敬请大神指正,不胜感激!源代码测试通过日期为:20 ...

  3. Webwork 学习之路【06】Action 调用

    一路走来,终于要开始 webwork 核心业务类的总结,webwork 通过对客户端传递的 web 参数重新包装,进行执行业务 Action 类,并反馈执行结果,本篇源码分析对应下图 WebWork ...

  4. Python学习一:序列基础详解

    作者:NiceCui 本文谢绝转载,如需转载需征得作者本人同意,谢谢. 本文链接:http://www.cnblogs.com/NiceCui/p/7858473.html 邮箱:moyi@moyib ...

  5. Python学习二:词典基础详解

    作者:NiceCui 本文谢绝转载,如需转载需征得作者本人同意,谢谢. 本文链接:http://www.cnblogs.com/NiceCui/p/7862377.html 邮箱:moyi@moyib ...

  6. IP2——IP地址和子网划分学习笔记之《子网掩码详解》

    2018-05-04 16:21:21   在学习掌握了前面的<进制计数><IP地址详解>这两部分知识后,要学习子网划分,首先就要必须知道子网掩码,只有掌握了子网掩码这部分内容 ...

  7. Linux学习之文件特殊权限详解(SetUID、SetGID、Sticky BIT)(十一)

    Linux学习之文件特殊权限详解(SetUID.SetGID.Sticky BIT) 目录 SetUID SetGID Sticky BIT SetUID SetUID简介 只有可以执行的二进制程序和 ...

  8. 重新学习MySQL数据库7:详解MyIsam与InnoDB引擎的锁实现

    重新学习Mysql数据库7:详解MyIsam与InnoDB引擎的锁实现 说到锁机制之前,先来看看Mysql的存储引擎,毕竟不同的引擎的锁机制也随着不同. 三类常见引擎: MyIsam :不支持事务,不 ...

  9. 《从0到1学习Flink》—— Flink 配置文件详解

    前面文章我们已经知道 Flink 是什么东西了,安装好 Flink 后,我们再来看下安装路径下的配置文件吧. 安装目录下主要有 flink-conf.yaml 配置.日志的配置文件.zk 配置.Fli ...

  10. hibernate学习(3)——api详解对象(2)

    1.   Transaction 事务 事务的操作: 开启事务 beginTransaction() 获得事务 getTransaction() 提交事务:commit() 回滚事务:rollback ...

随机推荐

  1. Iframe指定页面,并使其与该页面显示一致

    <%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding= ...

  2. msysGit管理GitHub代码

    msysGit管理GitHub代码   代码的管理,在日常开发中是很重要的环节,程序员的修炼三部曲——版本控制,单元测试,项目自动化. 本篇就简单的说说通过msysGit来管理GitHub中的代码,实 ...

  3. 曲演杂坛--使用CTE时踩的小坑:No Join Predicate

    在一次系统优化中,意外发现一个比较“坑”的SQL,拿出来供大家分享. 生成演示数据: --====================================== --检查测试表是否存在 IF(O ...

  4. docker-7 docker在阿里云的使用

    在传统模式中,开发团队在开发环境中完成软件开发,自己做了一遍单元测试, 测试通过,ᨀ交到代码版本管理库.运维把应用部署到测 试环境, QA 进行测试,没问题后通知部署人员发布到生产环境. 在上述过程中 ...

  5. 绕过校园网的共享限制 win10搭建VPN服务器实现--从入门到放弃

    一.开篇立论= =.. 上次说到博主在电脑上搭建了代理服务器来绕过天翼客户端的共享限制,然而经过实际测试还不够完美,所以本着生命不息,折腾不止的精神,我又开始研究搭建vpn服务器= =... (上次的 ...

  6. 提升效率(时间准确性),减少时间和资源的消耗——由89C52/89C51的定时器中断引出的一些问题

    尽量用最少的文字描述清楚问题. 事情起因是这样的: 要做遥控小车的平台迁移,STM32开发板无法方便地供电,因此又拿出了尘封的51(STC89C52RC),搭配上最小系统板就可以用排针加杜邦线供电了. ...

  7. DevOps Workshop 研发运维一体化第一场(微软亚太研发集团总部)

    准备了近两周,写了大量的操作手册,设计了大量的动手实验场景,终于在中关村的微软大厦完成了两天的DevOps培训. 最初报名160人,按照之前的培训经验,一般能到一半就不错了,没想到这次现场登记人员就超 ...

  8. nodejs模块——fs模块

    fs模块用于对系统文件及目录进行读写操作. 一.同步和异步 使用require('fs')载入fs模块,模块中所有方法都有同步和异步两种形式. 异步方法中回调函数的第一个参数总是留给异常参数(exce ...

  9. hdu1247 Hat’s Words

    地址:http://acm.split.hdu.edu.cn/showproblem.php?pid=1247 题目: Hat's Words Time Limit: 2000/1000 MS (Ja ...

  10. NOIP2012pj摆花[DP 多重背包方案数]

    题目描述 小明的花店新开张,为了吸引顾客,他想在花店的门口摆上一排花,共m盆.通过调查顾客的喜好,小明列出了顾客最喜欢的n种花,从1到n标号.为了在门口展出更多种花,规定第i种花不能超过ai盆,摆花时 ...