zoukankan      html  css  js  c++  java
  • 浅谈struts2之chain

    转自:http://blog.csdn.net/randomnet/article/details/8656759

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

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

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

      struts.xml:

    Action1.java

    [java] view plain copy print?


    action2

         <action name="action2" class="web.action.Action2">    
         <interceptor-ref name="defaultStack"></interceptor-ref>      
           <result>/result2.jsp</result>    
       </action>          
    </package>    
    

    [java] view plain copy print?
    public class Action1 extends ActionSupport {
    private String str1;
    private String str2;

     public String execute() throws Exception {    
            
        return SUCCESS;    
    
    }    
    
    public String getStr1() {    
        return str1;    
    }    
    public void setStr1(String str1) {    
        this.str1 = str1;    
    }    
    public String getStr2() {    
        return str2;    
    }    
    public void setStr2(String str2) {    
        this.str2 = str2;    
    }    
    

    }

    Action2.java
    [java] view plain copy print?
    public class Action2 extends ActionSupport {
    private String str1;
    private String str2;

     public String execute() throws Exception {    
               
        return SUCCESS;    
    
    }    
    
    public String getStr1() {    
        return str1;    
    }    
    public void setStr1(String str1) {    
        this.str1 = str1;    
    }    
    public String getStr2() {    
        return str2;    
    }    
    public void setStr2(String str2) {    
        this.str2 = str2;    
    }    
    

    }
    接着再上jsp文件:

    result1.jsp

    [java] view plain copy print?

    str1:
    str2:
    result2.jsp [java] view plain copy print? str1:${str1 }
    str2:${str2 } 其实整个流程如下图所示:

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

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

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

    下面进入探讨阶段:

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

    [java] view plain copy print?
    public class Action1 extends ActionSupport {
    private String str1;
    private String str2;

     public String execute() throws Exception {    
        str1="set in action1";                  
        return SUCCESS;    
    }    
    

    //省掉get,set
    }

    再次来运行.
      在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 plain copy print?

      str2:<input type="text" name="str2"><br/>    
      <input type="submit">     
    

    然后重新运行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 plain copy print?

        
                  
    ......省略..........    
        
                 
    ..................省略...........................    
        
                     
                
                       
         
    

        
    

    记注意这两个拦截器的先后顺序:先是chain,然后才是params

    这也就决定了上图中的执行顺序是:先执行5的动作后执行6的动作.

    严格说来,上图中5,6,7,8的动作顺序描述,也不是很严谨,

    真要说完全正确的执行顺序,实际上是先5,7然后再执行6,7,8.

    关于这一点,只需要在调试状态上跟踪下action2中的set方法的调用堆栈就能理解.

    好了,接下来我们说说chain和params的定义.还是在struts-default.xml中

       
                 
          
    


    要说chain类型的result,实际上就是构建一条链接,把访问路径上的action对象全放在这个链条上,

    先看下com.opensymphony.xwork2.interceptor.ChainingInterceptor.intercept(ActionInvocation invocation)

    找到关键代码: OgnlUtil.copy(o, invocation.getAction(), ctxMap, excludes, includes);

    这就是把action链条上,上一个action还有上上个action.....总之把action链条上前面访问的所有action对象

    都执行OgnlUtil.copy(.......),也就是把它们的valuestack中的值都赋给当前action的valuestack

    举个简单例子,有三个action

    action1,action2,action3

    当执行action2时,会把action1中valuestack的值赋给action2的valuestack

    当执行action3时,会把先后把action1和action2中valuestack的值赋给action3的valuestack

    依次类推.......

    再来看下:com.opensymphony.xwork2.interceptor.ParametersInterceptor.doIntercept(ActionInvocation invocation)

    其中关键方法调用: setParameters(action, stack, parameters);

    把parameters中的内容赋给valuestack

    但是,在实际使用过程,不推荐滥用chain

    因为正如之前举的例子一样,当chain上有两个action的时候,

    赋值过程实际上执行了3次=1+2:parameters到action1,action1到action2,parameters到action2

    以此类推:有3个action时,赋值过程=6次=1+2+3

    ........

    所以当链条上的action太多时,其实很费油的啦...

    具体过程,空了画个图来表示下,大家就更容易明白了


  • 相关阅读:
    寒假短期学习计划
    PAT 1001 A+B 解题报告
    JavaScript 原型链、继承
    JavaScript 数据扁平化处理
    每周一篇React: 高阶 hoc_component 使用
    每天一道算法题: day1 翻转图像
    项目中下载加权,你是怎么做的,欢迎评论。
    前端封装验证码方法,封装验证码类
    文件下载之后默认不打开实现方式
    文件下载之后默认不打开实现方式
  • 原文地址:https://www.cnblogs.com/jixu8/p/5966173.html
Copyright © 2011-2022 走看看