深度解析struts2结果类型之chain

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

    先解释下chain吧:

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

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

      先看一个chain的例子:

  struts.xml:

      

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

   Action1.java

  

[java]  view plain copy print ?
  1. public class Action1 extends ActionSupport {  
  2.     private String str1;  
  3.     private String str2;  
  4.       
  5.      public String execute() throws Exception {  
  6.           
  7.         return SUCCESS;  
  8.   
  9.     }  
  10.   
  11.     public String getStr1() {  
  12.         return str1;  
  13.     }  
  14.     public void setStr1(String str1) {  
  15.         this.str1 = str1;  
  16.     }  
  17.     public String getStr2() {  
  18.         return str2;  
  19.     }  
  20.     public void setStr2(String str2) {  
  21.         this.str2 = str2;  
  22.     }  
  23.   
  24. }  


Action2.java

[java]  view plain copy print ?
  1. public class Action2 extends ActionSupport {  
  2.     private String str1;  
  3.     private String str2;  
  4.       
  5.      public String execute() throws Exception {  
  6.              
  7.         return SUCCESS;  
  8.   
  9.     }  
  10.   
  11.     public String getStr1() {  
  12.         return str1;  
  13.     }  
  14.     public void setStr1(String str1) {  
  15.         this.str1 = str1;  
  16.     }  
  17.     public String getStr2() {  
  18.         return str2;  
  19.     }  
  20.     public void setStr2(String str2) {  
  21.         this.str2 = str2;  
  22.     }  
  23.                   
  24. }  

 

接着再上jsp文件:

result1.jsp

 

[html]  view plain copy print ?
  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

[html]  view plain copy print ?
  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 plain copy print ?
  1. public class Action1 extends ActionSupport {  
  2.     private String str1;  
  3.     private String str2;  
  4.       
  5.      public String execute() throws Exception {  
  6.         str1="set in action1";                
  7.         return SUCCESS;  
  8.     }  
  9. //省掉get,set  
  10. }  

再次来运行.
  在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 plain copy print ?
  1. <form action="action1.action" method="post">  
  2.    
  3.       str2:<input type="text" name="str2"><br/>  
  4.       <input type="submit">   
  5. </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为准


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

  

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

  1)chain

       2)params

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

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

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

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值