Webwork【05】请求跳转前 xwork.xml 的读取
个人理解 WebWork 与 Struts2 都是将xml配置文件作为 Controler 跳转的基本依据,WebWork 跳转 Action 前 xml 文件的读取依赖 xwork-1.0.jar,底层由 xwork实现,这部门代码读起来不是很轻松,在此做下记录供后续查阅和项目借鉴。今天的代码分析对应 下图 WebWork 框架流转图中红框框的地方。

WebWork xml配置文件读取的入口、后续的所有处理都是 Action 调用类 DefaultActionProxy 这句代码:
this.config = ConfigurationManager.getConfiguration().getRuntimeConfiguration().getActionConfig(namespace, actionName);
1. 框架中类图关系

2. ConfigurationManager
- ConfigurationManager 做为整个 xwork 获取配置信息的管理者,掌控 Configuration 与 XmlConfigurationProvider 两大类的实例化时机;
- ConfigurationManager的 getConfiguration()方法实现如下:
public static synchronized Configuration getConfiguration() {
if (configurationInstance == null) {
configurationInstance = new DefaultConfiguration();
configurationInstance.reload();
} else {
conditionalReload();
}
return configurationInstance;
}
- 注意框架中的这个方法前面的修饰符是 synchronized 并发线程不能同时访问该函数;
- 可以通过 setConfiguration方法设置一个 configurationInstance,如果没有设置,返回XWork的默认实现类, DefaultConfiguration;
3. DefaultConfiguration
- DefaultConfiguration 实现接口 Configuration ,其中含有内部类 RuntimeConfigurationImpl 实现了 RuntimeConfiguration 接口;
- 入口中DefaultActionProxy的构造函数中调用的:ConfigurationManager.getConfiguration().getRuntimeConfiguration().getActionConfig 默认的实现为 RuntimeConfigurationImpl ;
- ConfigurationManager 在实例化 DefaultConfiguration 对象后,紧接着调用了该对象的 reload();
public synchronized void reload() throws ConfigurationException {
this.packageContexts.clear();
for (Iterator iterator = ConfigurationManager.getConfigurationProviders().iterator(); iterator.hasNext();) {
ConfigurationProvider provider = (ConfigurationProvider) iterator.next();
provider.init(this);
}
rebuildRuntimeConfiguration();
}
- reload() 通过遍历 ConfigurationManager 中的configurationProviders链表,来逐个初始化 XWork 的配置信息。默认只有一个 ConfigurationProvider,也就是 XmlConfigurationProvider,同样只会读取一个XWork的配置信息,就是xwork.xml;
- 这里要注意一下,大项目都是许多工程师并发编写,一个xwork.xml 配置文件显示是不能满足各个模块一起开发的要求,这里需要编写一个类去继承 XmlConfigurationProvider,这个类需要将项目中分散在各个模块下的 xwork.xml 配置文件整合起来,写入到加载到 configurationProviders 链表当中(实现方式多种多样,看项目具体情况);
ConfigurationManager的 getConfigurationProviders方法实现如下:
public static List getConfigurationProviders() {
synchronized (configurationProviders) {
if (configurationProviders.size() == 0) {
configurationProviders.add(new XmlConfigurationProvider());
}
return configurationProviders;
}
}
- 在没继承 XmlConfigurationProvider 情况下,reload 函数里的 For 循环只会执行一次,调用XmlConfigurationProvider的 init方法;
- 调用该方法时, DefaultConfiguration把自身作为参数传了进去。 之后 XmlConfigurationProvider 的 init 方法会通过自身的loadConfigurationFile方法回调DefaultConfiguration的addPackageConfig方法将解析出的 Action 配置信息存放回 DefaultConfiguration 的Map 类型成员变量 packageContexts 中,供其内部类 RuntimeConfigurationImpl 的方法getActionConfig 返回某一个 Action 配置信息时查找使用;
- getActionConfig 返回的 ActionConfig 是 XWork 的一个类,包含了某一个 Action 的所有配置信息以及执行后的所有可能结果等;
- XmlConfigurationProvider 的 init 方法会通过自身的 loadConfigurationFile 方法首先读取xwork.xml配置信息,然后通过发现include标签找到其他配置文件去读取;
- 该机制保证了用户可以将一个庞大的XWork配置文件拆分为多个,在 xwork.xml通过 include标签引用进来,但要注意同名的 Action的覆盖问题[和上面说的注意区别]。
- loadConfigurationFile 通过递归解析完所有的配置文件,并将他们放入DefaultConfiguration的Map类型成员变量packageContexts中。
具体代码如下:
private void loadConfigurationFile(String fileName, DocumentBuilder db) {
if (!includedFileNames.contains(fileName)) {
if (LOG.isDebugEnabled()) {
LOG.debug("Loading xwork configuration from: " + fileName);
}
includedFileNames.add(fileName);
Document doc = null;
InputStream is = null;
try {
is = getInputStream(fileName);
if (is == null) {
throw new Exception("Could not open file " + fileName);
}
doc = db.parse(is);
} catch (Exception e) {
final String s = "Caught exception while loading file " + fileName;
LOG.error(s, e);
throw new ConfigurationException(s, e);
} finally {
if (is != null) {
try {
is.close();
} catch (IOException e) {
LOG.error("Unable to close input stream", e);
}
}
}
Element rootElement = doc.getDocumentElement();
NodeList children = rootElement.getChildNodes();
int childSize = children.getLength();
for (int i = 0; i < childSize; i++) {
Node childNode = children.item(i);
if (childNode instanceof Element) {
Element child = (Element) childNode;
final String nodeName = child.getNodeName();
if (nodeName.equals("package")) {
addPackage(child);
} else if (nodeName.equals("include")) {
String includeFileName = child.getAttribute("file");
loadConfigurationFile(includeFileName, db);
}
}
}
if (LOG.isDebugEnabled()) {
LOG.debug("Loaded xwork configuration from: " + fileName);
}
}
}
4. 这部分代码闪光的地方
- XmlConfigurationProvider 和 DefaultConfiguration 分别实现 ConfigurationProvider与 Configuration 接口,可以仔细看下接口中定义的抽象方法,十分合理,为程序的可扩展性提供了基础,做到了“对修改封闭,对扩展开放”。
- ConfigurationManager 采用了工厂模式来作为一个统一的入口 ,掌握了 DefaultConfiguration 与 ConfigurationProvider 的实例化时机,实例化采用单例模式,让两类的实例化对象有且只有一个,即解耦两类的同时保证了程序的高内聚,十分考究。
- DefaultConfiguration 的内部类的使用让程序的设计眼前一类,在看到它之后我一直在思考,为什么不将 内部类 RuntimeConfigurationImpl 单独作为一个类交由 ConfigurationManager 统一管理?
- RuntimeConfigurationImpl 如果交由ConfigurationManager 统一管理非常的不合理,RuntimeConfigurationImpl 中的唯一属性 namespaceActionConfigs 由外部类初始化填入, ConfigurationManager 到 赋值 namespaceActionConfigs 属性的过程:
ConfigurationManager.getConfiguration() --- Configuration.reload() --- Configuration.rebuildRuntimeConfiguration() -- Configuration.buildRuntimeConfiguration() -- RuntimeConfigurationImpl(namespaceActionConfigs)
- 内部类 RuntimeConfigurationImpl 可以随意使用外部类的成员变量(包括私有)而不用生成外部类的对象,隐藏你不想让别人知道的操作,使整个程序编码更加简洁。
- 这几个类中 方法前的修饰符,用的十分合理,包括private,protected。对多线程访问的合理控制。
Webwork【05】请求跳转前 xwork.xml 的读取的更多相关文章
- Webwork 学习之路【05】请求跳转前 xwork.xml 的读取
个人理解 WebWork 与 Struts2 都是将xml配置文件作为 Controler 跳转的基本依据,WebWork 跳转 Action 前 xml 文件的读取依赖 xwork-1.0.jar, ...
- [Python] 跳过前几行快速读取文件内容:islice
from itertools import islice start = 1 # 跳过第一行idx=0,从idx=1开始读取文件 with codecs.open('data.json', encod ...
- 为什么不能将客户端的连接请求跳转或转发到本机lo回环接口上?
一.为什么不能将本机的请求跳转/转发到回环接口上? 如上图一样,服务器对外只开放了一个80端口,但是web服务监听在了lo 接口上8080端口上,现在要实现外网通过访问服务器的80端口,来提供web服 ...
- 【抄袭】VB.NET扩展WebBrowser,拥有跳转前获取URL的能力
来自 http://www.cnblogs.com/yuanjw/archive/2009/02/09/1386789.html 我仅做VB化,并优化了事件消息 Imports System.Comp ...
- Linux运维之——每日小技巧,获取网站请求数的前20个IP
获取网站请求书的前20个IP |grep tcp|awk '{print $5}'|awk -F: '{print $1}'|sort|uniq -c|sort -nr|head -n20
- 跳转前暂停几秒js如何实现
jquery如何实现跳转前暂停几秒 今天有个需求,类似答题的,需要显示结果后再跳转. 此处直接通过settimeout实现. 代码如下: url = 'www.baidu.com'; setTimeo ...
- XML数据读取方式性能比较(一)
原文:XML数据读取方式性能比较(一) 几个月来,疑被SOA,一直在和XML操作打交道,SQL差不多又忘光了.现在已经知道,至少有四种常用人XML数据操作方式(好像Java差不多),不过还没有实际比较 ...
- php xml 文件读取 XMLReader
php xml 文件读取 <?php /** $xmlString = '<xml> <persons count="10"> <person ...
- 利用反射与dom4j读取javabean生成对应XML和读取XML得到对应的javabean对象集合
转自:http://blog.csdn.net/zhao19861029/article/details/8473245 首先实现生成对应的JAVAbean的XML文件方法 /** * DMO4J写入 ...
随机推荐
- 新闻编辑室第三季/全集The Newsroom迅雷下载
第三季 The Newsroom Season 3 (2014)看点:今日他们终于公布了续订第三季的消息,但同时也宣称第三季将会是<新闻编辑室>的最终季,对剧迷们来说可谓苦乐参半.讲述了一 ...
- Android NDK:Aborting..Stop的处理方法
在eclipse中配置cocos2d-x的android环境时,遇到这样的错误提示 网上搜索了一下,说是在NDK_MODULE_PATH环境变量下未找到所需要的Android.mk文件,后来仔细研究了 ...
- Java并发编程的艺术(九)——批量获取多条线程的执行结果
当向线程池提交callable任务后,我们可能需要一次性获取所有返回结果,有三种处理方法. 方法一:自己维护返回结果 // 创建一个线程池 ExecutorService executorServic ...
- perf使用示例1
perf使用示例1 perf - Performance analysis tools for Linux Performance counters for Linux are a new kerne ...
- QT 5.12 安装MinGW 7.3.0 32bit
一.下载MinGW 7.3.0 32bit for QT 5.12 链接:https://pan.baidu.com/s/1IKDhvxEbKIgmWyQQhpdnTw提取码:ubxc 二.解压缩并将 ...
- Python调用C/C++程序
编程中会遇到调用其他语言到库,这里记录一下Python调用C++. Python底层是C, 所以调用C还是比较方便.调用C++有些麻烦. Python提供了ctypes, 方便将Python类型转为C ...
- centos 下 mysql+keepalived实现双主自由切换
目录 ip规划 mysql双主配置 keepalived配置 mysql1中keepalived的配置 mysql2中keepalived的配置 VIP漂移检测 本文的目的是搭建一个互为主从的mysq ...
- IOS中的网络编程详解
在移动互联网时代,几乎所有应用都需要用到网络,比如QQ.微博.网易新闻.优酷.百度地图,只有通过网络跟外界进行数据交互.数据更新,应用才能保持新鲜.活力,如果没有了网络,也就缺少了数据变化,无论外观多 ...
- 推文《阿里凑单算法首次公开!基于Graph Embedding的打包购商品挖掘系统解析》笔记
推文<阿里凑单算法首次公开!基于Graph Embedding的打包购商品挖掘系统解析>笔记 从17年5月份开始接触Graph Embedding,学术论文读了很多,但是一直不清楚这技术是 ...
- 深度学习哪家强?吴恩达、Udacity和Fast.ai的课程我们替你分析好了
http://www.jianshu.com/p/28f5473c66a3 翻译 | AI科技大本营(rgznai100) 参与 | reason_W 引言 过去2年,我一直积极专注于深度学习领域.我 ...