Webwork 学习之路(五)请求跳转前 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()方法实现如下:

1     public static synchronized Configuration getConfiguration() {
2         if (configurationInstance == null) {
3             configurationInstance = new DefaultConfiguration();
4             configurationInstance.reload();
5         } else {
6             conditionalReload();
7         }
8         return configurationInstance;
9     }

  •  注意框架中的这个方法前面的修饰符是 synchronized 并发线程不能同时访问该函数;
  •  可以通过 setConfiguration方法设置一个 configurationInstance,如果没有设置,返回XWork的默认实现类, DefaultConfiguration;

回到顶部

3. DefaultConfiguration

  •  DefaultConfiguration 实现接口 Configuration ,其中含有内部类 RuntimeConfigurationImpl 实现了 RuntimeConfiguration 接口;
  •  入口中DefaultActionProxy的构造函数中调用的:ConfigurationManager.getConfiguration().getRuntimeConfiguration().getActionConfig 默认的实现为 RuntimeConfigurationImpl ;
  •  ConfigurationManager 在实例化 DefaultConfiguration 对象后,紧接着调用了该对象的 reload();

1     public synchronized void reload() throws ConfigurationException {
2         this.packageContexts.clear();
3         for (Iterator iterator = ConfigurationManager.getConfigurationProviders().iterator(); iterator.hasNext();) {
4             ConfigurationProvider provider = (ConfigurationProvider) iterator.next();
5             provider.init(this);
6         }
7         rebuildRuntimeConfiguration();
8     }

  • 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中。   

具体代码如下:

 1 private void loadConfigurationFile(String fileName, DocumentBuilder db) {
 2         if (!includedFileNames.contains(fileName)) {
 3             if (LOG.isDebugEnabled()) {
 4                 LOG.debug("Loading xwork configuration from: " + fileName);
 5             }
 6             includedFileNames.add(fileName);
 7             Document doc = null;
 8             InputStream is = null;
 9             try {
10                 is = getInputStream(fileName);
11                 if (is == null) {
12                     throw new Exception("Could not open file " + fileName);
13                 }
14                 doc = db.parse(is);
15             } catch (Exception e) {
16                 final String s = "Caught exception while loading file " + fileName;
17                 LOG.error(s, e);
18                 throw new ConfigurationException(s, e);
19             } finally {
20                 if (is != null) {
21                     try {
22                         is.close();
23                     } catch (IOException e) {
24                         LOG.error("Unable to close input stream", e);
25                     }
26                 }
27             }
28             Element rootElement = doc.getDocumentElement();
29             NodeList children = rootElement.getChildNodes();
30             int childSize = children.getLength();
31             for (int i = 0; i < childSize; i++) {
32                 Node childNode = children.item(i);
33                 if (childNode instanceof Element) {
34                     Element child = (Element) childNode;
35                     final String nodeName = child.getNodeName();
36                     if (nodeName.equals("package")) {
37                         addPackage(child);
38                     } else if (nodeName.equals("include")) {
39                         String includeFileName = child.getAttribute("file");
40                         loadConfigurationFile(includeFileName, db);
41                     }
42                 }
43             }
44             if (LOG.isDebugEnabled()) {
45                 LOG.debug("Loaded xwork configuration from: " + fileName);
46             }
47         }
48     }

回到顶部

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。对多线程访问的合理控制。

作者:Orson 
出处:http://www.cnblogs.com/java-class/ 
如果,您认为阅读这篇博客让您有些收获,不妨点击一下右下角的【推荐】 
如果,您希望更容易地发现我的新博客,不妨点击一下左下角的【关注我】 
如果,您对我的博客内容感兴趣,请继续关注我的后续博客,我是【Orson】 

本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段 声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。 

转自:http://www.cnblogs.com/java-class/p/5125183.html

时间: 2024-09-15 09:20:45

Webwork 学习之路(五)请求跳转前 xwork.xml 的读取的相关文章

Webwork 学习之路(六)Action 调用

阅读目录 1.这部分框架类关系 2.Webwork 获取和包装 web 参数 3.DefaultActionProxyFactory.DefaultActionProxy.DefaultActionInvocation       一路走来,终于要开始 webwork 核心业务类的总结,webwork 通过对客户端传递的 web 参数重新包装,进行执行业务 Action 类,并反馈执行结果,本篇源码分析对应下图 WebWork 框架流转图中红色框的地方. 回到顶部 1.这部分框架类关系 回到顶部

Webwork 学习之路(三)核心类 ServletDispatcher 的初始化

阅读目录 1. Webwork 与 Xwork 2.Webwork配置 3.核心类 ServletDispatcher 和 它的初始化 回到顶部 1. Webwork 与 Xwork      搭建环境需要的的jar 为:webwork-core-1.0.jar,xwork-1.0.jar,搭建webwork 需要xwork 的jar呢?原因是这样的,WebWork2 被构建在XWork之上,以XWork为基础.通过使用XWork的命令模式框架和拦截器框架,提供了一个支持Web功能.能快速构建W

Webwork 学习之路(一)Webwork与 Struct 的前世今生

 Struts 1是全世界第一个发布的MVC框架,它由Craig McClanahan在2001年发布,该框架一经推出,就得到了世界上Java Web开发者的拥护,经过长达6年时间的锤炼,Struts 1框架更加成熟.稳定,性能也有了很好的保证.         到目前为止,Struts 1依然是世界上使用最广泛的MVC框架.目前,基于Web的MVC框架非常多,发展也很快,每隔一段时间就有一个新的MVC框架发布.     虽然Struts 2号称是一个全新的框架,但这仅仅是相对Struts 1而

Webwork 学习之路(四)Configuration 详解

阅读目录 1. Configuration 2. DefaultConfiguration 3. DelegatingConfiguration 4. webwork[三][四]小结   Webwork做为经典的Web MVC 框架,个人觉得源码中配置文件这部分代码的实现十分考究.   支持自定义自己的配置文件.自定义配置文件读取类.自定义国际化支持.   可以作为参考,单独引入到其他项目中,下面是Configuration相关类的继承关系:     回到顶部 1. Configuration

Webwork 学习之路(二)前端OGNL试练

阅读目录 1.OGNL 出现的意义 2.OGNL项目实战 回到顶部 1.OGNL 出现的意义    在mvc中,数据是在各个层次之间进行流转是一个不争的事实.而这种流转,也就会面临一些困境,这些困境,是由于数据在不同世界中的表现形式不同而造成的: a. 数据在页面上是一个扁平的,不带数据类型的字符串,无论你的数据结构有多复杂,数据类型有多丰富,到了展示的时候,全都一视同仁的成为字符串在页面上展现出来. b. 数据在Java世界中可以表现为丰富的数据结构和数据类型,你可以自行定义你喜欢的类,在类与

请求-初学C#,专业信息管理,方向ERP,求大神明示学习之路

问题描述 初学C#,专业信息管理,方向ERP,求大神明示学习之路 我现在是个大二的学生了,现在在学习C#的基本入门语法,以后想做ERP这类方向,请求各位前辈指教一下我接下来应该学习C#的那些方向 解决方案 看看 <C#入门经典> 这本书 先搞懂基础

Qt 学习之路 2 --- 读书笔记

一.文章来由 来自豆子老师非常好的一本Qt教程,但是只有网络版,所以用这个做笔记了,不动笔墨不读书嘛~~ 二.读书笔记 1.Qt 学习之路 2(2):Qt 简介 1.1 关于 Qt 的一站式解决 Qt 是一个著名的 C++ 应用程序框架.但并不只是一个 GUI 库,因为 Qt 十分庞大,并不仅仅是 GUI 组件.使用 Qt,在一定程度上你获得的是一个"一站式"的解决方案:不再需要研究 STL,不再需要 C++ 的,不再需要到处去找解析 XML.连接数据库.访问网络的各种第三方库,因为

我现在是一个C#程序员,想问问学习之路

问题描述 我现在是一个C#程序员,已经工作两年了,怎么说呢?现在有点迷茫,不知道要学些什么,能用一些什么,现在把NHibernate看了遍,然后呢?框架,架构,设计,计算还是什么,希望有人能解决这个问题,C#程序员学习的未来道路,现在要看的书,要用的技术- 解决方案 解决方案二:可以升入研究一下其他的.NET技术嘛.wpf,wcf,wf,siverlight等技术.解决方案三: 解决方案四:这些是没有的,关键还是要学历,考研,才是出路解决方案五:引用3楼chongyiren的回复: 这些是没有的

Linux命名空间学习教程(五)NET

本文讲的是Linux命名空间学习教程(五)NET,[编者的话]Docker核心解决的问题是利用LXC来实现类似VM的功能,从而利用更加节省的硬件资源提供给用户更多的计算资源.而 LXC所实现的隔离性主要是来自内核的命名空间, 其中pid.net.ipc.mnt.uts 等命名空间将容器的进程.网络.消息.文件系统和hostname 隔离开.本文是Linux命名空间系列教程的第五篇,重点介绍NET命名空间.DockerOne在撸代码的基础上进行了校对和整理. 阅读完上一篇关于NS namespac