转自: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太多时,其实很费油的啦...

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

浅谈struts2之chain的更多相关文章

  1. 浅谈 Struts2 面试题收藏

    Struts2面试题 一.工作原理 一个请求在Struts2框架中的处理大概分为以下几个步骤 1 客户端初始化一个指向Servlet容器(例如Tomcat)的请求 2 这个请求经过一系列的过滤器(Fi ...

  2. 小学生之浅谈Struts2与struts1的运行机制

    Struts1工作原理图: 1.初始化:struts框架的总控制器ActionServlet是一个Servlet,它在web.xml中配置成自动启动的Servlet,在启动时总控制器会读取配置文件(s ...

  3. 浅谈Struts2(二)

    一.struts2的跳转 1.action跳转JSP a.默认为forward <action name="action1" class="com.liquidxu ...

  4. 浅谈Struts2

    学过SSH框架很长一段时间了,一直没有很系统的总结一下,这里先简单谈谈Struts2. 为什么要用Struts2? 这里列举一些Servlet的缺点: 1.每写一个servlet在web.xml中都要 ...

  5. 浅谈Struts2拦截器的原理与实现

    拦截器与过滤器           拦截器是对调用的Action起作用,它提供了一种机制可以使开发者定义在一个action执行的前后执行的代码,也可以在一个action执行前阻止其执行.同时也是提供了 ...

  6. [SSH 2] 以网站主页面浅谈Struts2配置

    导读:前面总体的介绍了一下SSH框架,那么作为Struts这一支,具体是怎么配置的呢?本篇博客则主要是以自己做过的实例中的登录一条线,简单介绍一下struts2的配置,如有不妥之处,还请大家多提点提点 ...

  7. 浅谈Struts2(四)

    一.Struts2的拦截器(Intercept) 作用:把多个Action中的共有代码,提取至拦截器,从而减少Action中的冗余代码. 1.Action拦截器 a.编写interceptor类 pu ...

  8. 浅谈Struts2(三)

    一.Struts2收集client的参数 核心思路: <form method="post" action="XXXX"> <input ty ...

  9. 浅谈Struts2(一)

    一.Struts2引言 1.Struts2框架的概念 解决的MVC开发过程中,控制器(Controller)的通用问题. a.什么是MVC开发 MVC开发是一种编程思想,由设计者人为的把一个项目,划分 ...

随机推荐

  1. WCF在tcp通道下启用httpget

    关于tcp通道下,启用httpget,必须启用一个http的基地址,如果要启用元数据交换,host中必须开启服务描述. //01 create host Uri tcpBaseAddress = ne ...

  2. Selenium调用Chrome,Firefox,IE

    C#环境下,使用Selenium调用不同的浏览器,可以使用如下方法: IWebDriver driver = null; string Browser =null; if (Browser.Equal ...

  3. 修改tomcat的端口

  4. HDMI学习

    市面上大多4K显示器都配备了HDMI 1.4接口,仅能实现30Hz的刷新率,不足以带来流畅的显示效果, 酱紫情况,就算是搭配了HDMI 2.0高清线也是无法发挥其作用.只有更先进的HDMI 2.0标准 ...

  5. php js => splice 数组 插入 功能

    php    array_splice 手册详解 array_splice   - 把数组中的一部分去掉并用其它值取代 参数 input 输入的数组. offset 如果 offset 为正,则从 i ...

  6. flexbox布局

    一.侧轴对齐伸缩项目--align-items 它充许调整伸缩项目在侧轴(也就是y轴)的对齐方式,主要包括以下几个值: flex-start/baseline:伸缩项目在侧轴起点边的外边距紧靠住该行在 ...

  7. Java内存分配及变量存储位置实例讲解

    Java内存分配与管理是Java的核心技术之一,之前我们曾介绍过Java的内存管理与内存泄露以及Java垃圾回收方面的知识,今天我们再次深入Java核心,详细介绍一下Java在内存分配方面的知识.一般 ...

  8. 清空IE缓存

    1.打开IE Internet选项 点击设置 2.打开临时文件 点击 查看文件 将目录下的 文件全部删除  重新打开网站即可 到此IE缓存就被删除.

  9. cannot find module 'xml2js'

    运行nodejs网站报类似错误,缺少相应的报 在NodeJs安装目录,运行Node.js command prompt ,跳转到网站所在目录,运行npm install xml2js,安装缺少的模块, ...

  10. 金蝶K/3 Cloud 界面解析过程

    服务端 目前也就是iis服务器生成Json描述返回给不同的展现端最解析. 不同的展现端,可以有Silverlight.WPF.Html5.Winform 当然还有IOS和Android端做解析展现 对 ...