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, ...
- Webwork 学习之路【06】Action 调用
一路走来,终于要开始 webwork 核心业务类的总结,webwork 通过对客户端传递的 web 参数重新包装,进行执行业务 Action 类,并反馈执行结果,本篇源码分析对应下图 WebWork ...
- Webwork 学习之路【03】核心类 ServletDispatcher 的初始化
1. Webwork 与 Xwork 搭建环境需要的的jar 为:webwork-core-1.0.jar,xwork-1.0.jar,搭建webwork 需要xwork 的jar呢?原因是这样的,W ...
- Qt 学习之路 2(62):保存 XML
Home / Qt 学习之路 2 / Qt 学习之路 2(62):保存 XML Qt 学习之路 2(62):保存 XML 豆子 2013年8月26日 Qt 学习之路 2 9条评论 前面几章我们 ...
- Webwork 学习之路【08】结合实战简析Controller 配置
虽然现在 MVC 框架层出不穷,但做为 Struts 前身的 webwork. 其经典程度不亚于贝利之于足球,双 11 之于淘宝特卖. 本篇将结合 webwork controller 配置文件 xw ...
- Webwork 学习之路【07】文件上传下载
Web上传和下载应该是很普遍的一个需求,无论是小型网站还是大并发访问的交易网站.WebWork 当然也提供了很友好的拦截器来实现对文件的上传,让我们可以专注与业务逻辑的设计和实现,在实现上传和下载时顺 ...
- Webwork 学习之路【01】Webwork与 Struct 的前世今生
Struts 1是全世界第一个发布的MVC框架,它由Craig McClanahan在2001年发布,该框架一经推出,就得到了世界上Java Web开发者的拥护,经过长达6年时间的锤炼,Struts ...
- Webwork 学习之路【04】Configuration 详解
Webwork做为经典的Web MVC 框架,个人觉得源码中配置文件这部分代码的实现十分考究. 支持自定义自己的配置文件.自定义配置文件读取类.自定义国际化支持. 可以作为参考,单独引入到其他项目中, ...
- Webwork 学习之路【02】前端OGNL试练
1.OGNL 出现的意义 在mvc中,数据是在各个层次之间进行流转是一个不争的事实.而这种流转,也就会面临一些困境,这些困境,是由于数据在不同世界中的表现形式不同而造成的: a. 数据在页面上是一个扁 ...
随机推荐
- sql语句 在字段前面加0
目前数字如下: 1 2 3 10 想变成长度为5位,如果不够,前面补0, 写法如下 select right('00000'+ltrim(你的字段),5) 结果: 00001 00002 00003 ...
- 【JSP】JSP基础学习记录(四)—— Servlet
序: 众所周知JSP的基础也就是Servlet,如果单纯用Servlet类来响应用户的HTTP请求可以吗?答案是肯定的.JSP中的9个内置对象只是自动帮我们初始化的,没有他们一样可以实现web.只是工 ...
- 0012 win7x64安装CentOS7
00 准备工作 到VirtualBox官网下载Oracle VM VirtualBox 5.1.8:https://www.virtualbox.org/wiki/Downloads 到centos官 ...
- 正则表达式(/[^0-9]/g,'')中的"/g"是什么意思?
解答“正则表达式(/[^0-9]/g,'')中的"/g"是什么意思?”这个问题,也为了能够便于大家对正则表达式有一个更为综合和深刻的认识,我将一些关键点和容易犯糊涂的地方再系统总结 ...
- CentOS系统在不重启的情况下为虚拟机添加新硬盘
一.概述 用过虚拟机的都知道,如果在系统运行的时候去给虚拟机添加一块新设备,比如说硬盘,系统是读取不到这个新硬盘的,因为系统在启动的时候会去检测硬件设备.但是我们也可能会遇到这样的情况,比如正在运行比 ...
- VIM使用技巧总结
一.vim使用的基本配置 1: set nu //设置行号 2: set ts=4 //设置tab为4个空格大小 3: set expandtab //设置用空格代替tab 4: set ai //设 ...
- MySQL性能优化经验
核心 不做运算 md5() Order By Rand() 控制单表数据量 保持表字段苗条 平衡范式与冗余 拒绝3B Big SQL Big Transaction Big Batch 字段 用好数值 ...
- PHP正确的使用复数
<?php // 正确地显示复数 if(!function_exists('_plurals_format')) { /** * 正确的使用复数 * @access public * @auth ...
- WCF自定义Header
MiscWebSrvcInfClient client = new MiscWebSrvcInfClient("MiscWSBeanPort", ConfigurationMana ...
- 理解 OpenStack Swift (2):架构、原理及功能 [Architecture, Implementation and Features]
本系列文章着重学习和研究OpenStack Swift,包括环境搭建.原理.架构.监控和性能等. (1)OpenStack + 三节点Swift 集群+ HAProxy + UCARP 安装和配置 ( ...