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

WebWork xml配置文件读取的入口、后续的所有处理都是 Action 调用类 DefaultActionProxy 这句代码:

  1. 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方法实现如下:

  1. public static List getConfigurationProviders() {
  2. synchronized (configurationProviders) {
  3. if (configurationProviders.size() == 0) {
  4. configurationProviders.add(new XmlConfigurationProvider());
  5. }
  6. return configurationProviders;
  7. }
  8. }
  • 在没继承 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 属性的过程:
  1. ConfigurationManager.getConfiguration() --- Configuration.reload() --- Configuration.rebuildRuntimeConfiguration() --
  2.  
  3. Configuration.buildRuntimeConfiguration() -- RuntimeConfigurationImpl(namespaceActionConfigs)
  • 内部类 RuntimeConfigurationImpl 可以随意使用外部类的成员变量(包括私有)而不用生成外部类的对象,隐藏你不想让别人知道的操作,使整个程序编码更加简洁。
  • 这几个类中 方法前的修饰符,用的十分合理,包括private,protected。对多线程访问的合理控制。

Webwork【05】请求跳转前 xwork.xml 的读取的更多相关文章

  1. Webwork 学习之路【05】请求跳转前 xwork.xml 的读取

    个人理解 WebWork 与 Struts2 都是将xml配置文件作为 Controler 跳转的基本依据,WebWork 跳转 Action 前 xml 文件的读取依赖 xwork-1.0.jar, ...

  2. [Python] 跳过前几行快速读取文件内容:islice

    from itertools import islice start = 1 # 跳过第一行idx=0,从idx=1开始读取文件 with codecs.open('data.json', encod ...

  3. 为什么不能将客户端的连接请求跳转或转发到本机lo回环接口上?

    一.为什么不能将本机的请求跳转/转发到回环接口上? 如上图一样,服务器对外只开放了一个80端口,但是web服务监听在了lo 接口上8080端口上,现在要实现外网通过访问服务器的80端口,来提供web服 ...

  4. 【抄袭】VB.NET扩展WebBrowser,拥有跳转前获取URL的能力

    来自 http://www.cnblogs.com/yuanjw/archive/2009/02/09/1386789.html 我仅做VB化,并优化了事件消息 Imports System.Comp ...

  5. Linux运维之——每日小技巧,获取网站请求数的前20个IP

    获取网站请求书的前20个IP |grep tcp|awk '{print $5}'|awk -F: '{print $1}'|sort|uniq -c|sort -nr|head -n20

  6. 跳转前暂停几秒js如何实现

    jquery如何实现跳转前暂停几秒 今天有个需求,类似答题的,需要显示结果后再跳转. 此处直接通过settimeout实现. 代码如下: url = 'www.baidu.com'; setTimeo ...

  7. XML数据读取方式性能比较(一)

    原文:XML数据读取方式性能比较(一) 几个月来,疑被SOA,一直在和XML操作打交道,SQL差不多又忘光了.现在已经知道,至少有四种常用人XML数据操作方式(好像Java差不多),不过还没有实际比较 ...

  8. php xml 文件读取 XMLReader

    php xml 文件读取 <?php /** $xmlString = '<xml> <persons count="10"> <person ...

  9. 利用反射与dom4j读取javabean生成对应XML和读取XML得到对应的javabean对象集合

    转自:http://blog.csdn.net/zhao19861029/article/details/8473245 首先实现生成对应的JAVAbean的XML文件方法 /** * DMO4J写入 ...

随机推荐

  1. 安卓开发环境配置及HelloWorld

    一:JAVA 下载地址:http://www.oracle.com/technetwork/java/javase/downloads/jdk8-downloads-2133151.html 1.1 ...

  2. MySQL Test Suite使用

    MySQL Test Suite使用 MySQL自动测试套件(The MySQL Test Suite)用于对MySQL程序进行测试,包括各种功能与存储引擎.包含于MySQL与MariaDB版本代码中 ...

  3. YAML文件简介

    编程免不了要写配置文件,怎么写配置也是一门学问. YAML 是专门用来写配置文件的语言,非常简洁和强大,远比 JSON 格式方便. 本文介绍 YAML 的语法,以 JS-YAML 的实现为例.你可以去 ...

  4. Variational Inference

    作者:孙九爷链接:https://www.zhihu.com/question/41765860/answer/101915528来源:知乎著作权归作者所有.商业转载请联系作者获得授权,非商业转载请注 ...

  5. Python/Shell 正则表达式与运用

    正则表达式用的地方是很多的.比如字符串处理过程中.最近遇到记录一下. 1. 比如在shell中 #!/bin/bash str="date:2017-11-28 os:centos blac ...

  6. 很不错的python 机器学习博客

    http://www.cuijiahua.com/resource.html 曾看过的书,感觉一些很有用的学习资料,推荐给大家! Python基础: 网络教程推荐: 系统学习python3可以看廖雪峰 ...

  7. android bundle 对象 序列化

    Android使用Intent.putSerializable()进行数据传递,或者使用Bundle进行数据传递,实质上都是进行的Serializable数据的操作,说白了都是传递的原数据的一份拷贝, ...

  8. 如何配置官方peerDroid,使其运行起来

    一.Peer Droid是JXME协议到android平台的移植,开发者可以利用它来实现android设备以及传统PC机通讯的应用程序,peerDroid的官方demo主要是实现PC端peer和and ...

  9. LSTM简介以及数学推导(FULL BPTT)

    http://blog.csdn.net/a635661820/article/details/45390671 前段时间看了一些关于LSTM方面的论文,一直准备记录一下学习过程的,因为其他事儿,一直 ...

  10. (转)Unity3D中脚本的执行顺序和编译顺序(vs工程引用关系)

    自:http://www.cnblogs.com/champ/p/execorder.html 在Unity中可以同时创建很多脚本,并且可以分别绑定到不同的游戏对象上,它们各自都在自己的生命周期中运行 ...