chain

前一段时间,有关chain的机制着实困绕了许久.尽管网上有许多关于chain的解说,但要不是只谈大理论,不结合实例;要不就是只有示例,没有挖出示例背后的意义.

    先解释下chain吧:

  Chain:基本用途是构造成一条动作链。前一个动作将控制权转交给后一个动作,而前一个动作的状态在后一个动作里仍然保持着。动作链由Chaining拦截器负责处理,因为这个拦截器是defaultStack拦截器栈的一份子,多以你随时都可以使用动作链。

有人说:chain是共享valuestack;也有人说chain是共享表单参数.就我个人而言,以上两种说法都不见完全正确.

先看一个chain的例子:

  struts.xml:

Action1.java

[java] view plaincopyprint?

  1. <package name="default" extends="struts-default">
  2. <action name="action1" class="web.action.Action1">
  3. <result type="chain">action2</result>
  4. </action>
  5. <action name="action2" class="web.action.Action2">
  6. <interceptor-ref name="defaultStack"></interceptor-ref>
  7. <result>/result2.jsp</result>
  8. </action>
  9. </package>

[java] view plaincopyprint?

  1. public class Action1 extends ActionSupport {
  2. private String str1;
  3. private String str2;
  4. public String execute() throws Exception {
  5. return SUCCESS;
  6. }
  7. public String getStr1() {
  8. return str1;
  9. }
  10. public void setStr1(String str1) {
  11. this.str1 = str1;
  12. }
  13. public String getStr2() {
  14. return str2;
  15. }
  16. public void setStr2(String str2) {
  17. this.str2 = str2;
  18. }
  19. }

Action2.java

[java] view plaincopyprint?

  1. public class Action2 extends ActionSupport {
  2. private String str1;
  3. private String str2;
  4. public String execute() throws Exception {
  5. return SUCCESS;
  6. }
  7. public String getStr1() {
  8. return str1;
  9. }
  10. public void setStr1(String str1) {
  11. this.str1 = str1;
  12. }
  13. public String getStr2() {
  14. return str2;
  15. }
  16. public void setStr2(String str2) {
  17. this.str2 = str2;
  18. }
  19. }

接着再上jsp文件:

result1.jsp

[java] view plaincopyprint?

  1. <form action="action1.action" method="post">
  2. str1:<input type="text" name="str1"><br/>
  3. str2:<input type="text" name="str2"><br/>
  4. <input type="submit">
  5. </form>

result2.jsp

[java] view plaincopyprint?

  1. <s:debug/>
  2. str1:${str1 }
  3. <br/>
  4. str2:${str2 }

其实整个流程如下图所示:

运行结果也很简单,没有悬念:

  在result1.jsp输入:str1=111,str2=222

在result2.jsp显示:str1=111,str2=222

下面进入探讨阶段:

  首先修改下action1.java,在action1中,修改valuestack中的str1的,如下所示:

[java] view plaincopyprint?

  1. public class Action1 extends ActionSupport {
  2. private String str1;
  3. private String str2;
  4. public String execute() throws Exception {
  5. str1="set in action1";
  6. return SUCCESS;
  7. }
  8. //省掉get,set
  9. }

再次来运行.
  在result1.jsp输入:str1=111,str2=222

在result2.jsp显示:str1=111,str2=222

结果很奇怪?为什么在result2.jsp不是显示str1=set in action1? 难道action1.java中修改过后的str1的值没有写入valuestack

那我们看看result2.jsp中通过<s:debug/>打印出来的信息.

从debug信息可以看出:

1)在action1的valuestack中,str1的确被成功修改了.

2)但是action2中的valuestack中,str1还是停留在页面上输入的str1的值

难道action1中的valuestack没有共享到action2中的valuestack?

为了进一步了解事实真相,我们继续来做实验:

接下来,我在action2.java中的setStr1(String str)中设置断点,跟踪action2中str1的赋值情况

发现:str1其实是被赋了两次值:第一次是"set in action1",而第二次是"111"

如此就得到了如上所示的运行结果.

很奇怪是吧?

我猜测第二次赋值中的"111"来自jsp提交过后产生的表单参数对象,即parameters.

为了验证猜测,我们把result1.jsp中的str1的输入去掉,如下代码所示:

[html] view plaincopyprint?

[java] view plaincopyprint?

  1. <form action="action1.action" method="post">
  2. str2:<input type="text" name="str2"><br/>
  3. <input type="submit">
  4. </form>

然后重新运行result1.jsp

运行过程所下:

   在result1.jsp中输入str2=222

在result2.jsp中显示:str1=set in action1,str2=222

OK,如此,我们在action1中的对str1的修改成功传递给了action2,而action2中setStr1()也只执行了一次.

真相呼之欲出了,我们还是用一幅图来表示整个过程

如此,在执行第四步的时候,如果表单参数中和action1的valuestack中同时有str1这一项,

则表单参数中str1会覆盖action1的valuestack中的str1,最终action2的str1是以表单参数中的str1为准

好了,以上仅是根据运行结果作出的猜测和解释.

现在接着写下半部分:从源码的角度谈chain的机制

  因为我的源码全是通过反编译jar包得来,不能保证100%的正确性,若遇到不对的地方,请大家指出.也请大家先谅解

  在<<浅谈struts2之chain[1]>>最后,用了一个简略图来表示chain机制:

  

  但实际上,如果考虑valuestack的话,这幅图应该这样画:

  

  对于此图中,关键性两个步骤:5和6, 实际上涉及到两个拦截器:

  1)chain

2)params

  也就说,说chain方式的action之间共享valuestack是没有错的,说它们共享parameters也没有错

关键是它们的先后顺序及相互影响      我们来看一下struts-core-2.0.11.jar中struts-default.xml中对这两个拦截器的使用:

[java] view plaincopyprint?

    1. <pre class="html" name="code"><interceptor-stack name="defaultStack">
    2.    
    3. ......省略..........
    4. <interceptor-ref name="chain"/>
    5. ..................省略...........................
    6. <interceptor-ref name="params">
    7. </interceptor-stack>
    8. </pre><br>
    9. <pre></pre>
    10. <p>记注意这两个拦截器的先后顺序:先是chain,然后才是params</p>
    11. <p>这也就决定了上图中的执行顺序是:先执行5的动作后执行6的动作.</p>
    12. <p>严格说来,上图中5,6,7,8的动作顺序描述,也不是很严谨,</p>
    13. <p>真要说完全正确的执行顺序,实际上是先5,7然后再执行6,7,8.</p>
    14. <p>关于这一点,只需要在调试状态上跟踪下action2中的set方法的调用堆栈就能理解.</p>
    15. <p> </p>
    16. <p>好了,接下来我们说说chain和params的定义.还是在struts-default.xml中</p>
    17. <pre class="html" name="code">
    18. <interceptor name="chain" class="com.opensymphony.xwork2.interceptor.ChainingInterceptor"/>
    19.  <interceptor name="params" class="com.opensymphony.xwork2.interceptor.ParametersInterceptor"/>
    20. </pre>
    21. <p><br>
    22. 要说chain类型的result,实际上就是构建一条链接,把访问路径上的action对象全放在这个链条上,</p>
    23. <p>先看下com.opensymphony.xwork2.interceptor.ChainingInterceptor.intercept(ActionInvocation invocation)</p>
    24. <p>找到关键代码: OgnlUtil.copy(o, invocation.getAction(), ctxMap, excludes, includes);</p>
    25. <p>这就是把action链条上,上一个action还有上上个action.....总之把action链条上前面访问的所有action对象</p>
    26. <p>都执行OgnlUtil.copy(.......),也就是把它们的valuestack中的值都赋给当前action的valuestack</p>
    27. <p><span style="color:#ff6666">举个简单例子,有三个action</span></p>
    28. <p><span style="color:#ff6666">action1,action2,action3</span></p>
    29. <p><span style="color:#ff6666">当执行action2时,会把action1中valuestack的值赋给action2的valuestack</span></p>
    30. <p><span style="color:#ff6666">当执行action3时,会把先后把action1和action2中valuestack的值赋给action3的valuestack</span></p>
    31. <p><span style="color:#ff6666">依次类推.......</span></p>
    32. <p> </p>
    33. <p>再来看下:com.opensymphony.xwork2.interceptor.ParametersInterceptor.doIntercept(ActionInvocation invocation)</p>
    34. <p>其中关键方法调用: setParameters(action, stack, parameters);</p>
    35. <p>把parameters中的内容赋给valuestack</p>
    36. <p> </p>
    37. <p>但是,在实际使用过程,不推荐滥用chain</p>
    38. <p>因为正如之前举的例子一样,当chain上有两个action的时候,</p>
    39. <p>赋值过程实际上执行了3次=1+2:parameters到action1,action1到action2,parameters到action2</p>
    40. <p>以此类推:有3个action时,赋值过程=6次=1+2+3</p>
    41. <p>........</p>
    42. <p>所以当链条上的action太多时,其实很费油的啦...</p>
    43. <p>具体过程,空了画个图来表示下,大家就更容易明白了</p>
    44. <p> </p>
    45. <p><br>
    46. </p>
    47. <p>
    48. </p>
时间: 2024-10-06 04:44:04

chain的相关文章

设计模式之Chain of Responsibility(职责链)(转)

Chain of Responsibility定义 Chain of Responsibility(CoR) 是用一系列类(classes)试图处理一个请求request,这些类之间是一个松散的耦合,唯一共同点是在他们之间传递request. 也就是说,来了一个请求,A类先处理,如果没有处理,就传递到B类处理,如果没有处理,就传递到C类处理,就这样象一个链条(chain)一样传递下去. 如何使用? 虽然这一段是如何使用CoR,但是也是演示什么是CoR. 有一个Handler接口: public

hdu 5293 Tree chain problem(树链剖分+树形dp)

题目链接:hdu 5293 Tree chain problem 维护dp[u], sum[u],dp[u]表示以u为根节点的子树的最优值.sum[u]表示以u节点的所有子节点的dp[v]之和.对于边a,b,w,在LCA(a,b)节点的时候进行考虑.dp[u] = min{dp[u], Sum(a,b) - Dp(a,b) + sum[u] | (ab链上的点,不包括u } #pragma comment(linker, "/STACK:1024000000,1024000000")

HDU 3980 Paint Chain(博弈 SG)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3980 Problem Description Aekdycoin and abcdxyzk are playing a game. They get a circle chain with some beads. Initially none of the beads is painted. They take turns to paint the chain. In Each turn one p

- Component template should contain exactly one root element. If you are using v-if on multiple elements, use v-else-if to chain them instead. 解决方案

<template> <div>{{hello}}</div> <button @click="addOne">add one</button> <button @click="minusOne">minus one</button> </template> 在*.vue组件里有这么一段. 报错信息: (Emitted value instead of an instan

ios中事件的响应链(Responder chain)和传递链

事件的响应链涉及到的一些概念 UIResponder类,是UIKIT中一个用于处理事件响应的基类.窗又上的所有事件触发,都由该类响应(即事件处理入又).所以,窗又上的View及控制器都是 派生于该类的,例如UIView.UIViewController等. 调用UIResponder类提供的方法或属性,我们就可以捕捉到窗又上的所有响应 事件,并进行处理. 响应者链条是由多个响应者对象连接起来的链条,其中响应者对象是能处理事 件的对象,所有的View和ViewController都是响应者对象,利

docker0: iptables: No chain/target/match by that name错误处理

今天运行这个命令时报错 docker run -it --name Haproxy --link app1:app1 --link app2:app2 -p 6302:6301 -v ~/Projects/HAProxy:/tmp haproxy /bin/bash 报错信息: docker: Error response from daemon: failed to create endpoint Haproxy on network bridge: iptables failed: ipta

struts2 中chain、redirect、redirect-action的区别

struts2 中chain.redirect.redirectaction的区别 文章摘要: 一.Chain Result:这个result调用另外的一个action,连接自己的拦截器栈和result. ?actionName (默认) - 被调用的action的名字?namespace - 被调用的action的名称空间. 如果名称空间为空,这默认为当前名称空间?method - 用于指定目标action的另一个方法被调用. 如果空,默认为excute方法Redirect Action Re

C++设计模式 之 “数据结构” 模式:Composite、Iterator、Chain of Resposibility

"数据结构"模式 常常有一些组件在内部具有特定的数据结构,如果让客户程序依赖这些特定的数据结构,将极大地破坏组件的复用.这时候,将这些特定数据结构封装在内部,在外部提供统一的接口,来实现与特定数据结构无关的访问,是一种行之有效的解决方案. 典型模式 #Composite #Iterator #Chain of Resposibility part 1 Composite 模式 动机 #软件在某些情况下,客户代码过多地依赖于对象容器复杂的内部实现结构,对象容器内部实现结构(而非抽象接口)

HDU 5293(Tree chain problem-树链剖分)

Tree chain problem Time Limit: 6000/3000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others) Total Submission(s): 940    Accepted Submission(s): 248 Problem Description Coco has a tree, whose vertices are conveniently labeled by 1,2,-,n. Th

Chain of Responsibility模式

消息传递是面向对象开发中经常用到的机制,例如异常的传递,如果当前函数/类无法处理异常,可以将其抛到上一层.消息传递类似,如果一个类收到消息,如果当前类无法处理,可以将消息按照预先定义好的路径传递下去,直到有类可以处理这个消息.这就是Chain of Responsibility模式. Handle类中持有自己的指针/引用,指向某一个派生类.如果当前类无法处理消息,则调用派生类来处理. 实现: Handle.h #ifndef _HANDLE_H_ #define _HANDLE_H_ class