struts2 拦截器和actioninvocation、PreResultListener
Interceptor说明
Interceptor的接口定义没有什么特别的地方,除了init和destory方法以外,intercept方法是实现整个拦截器机制的核心方法。而它所依赖的参数ActionInvocation则是我们之前章节中曾经提到过的著名的Action调度者。
我在这里需要指出的是一个很重要的方法invocation.invoke()。这是ActionInvocation中的方法,而ActionInvocation是Action调度者,所以这个方法具备以下2层含义(详细看DefaultActionInvocation源代码):
1. 如果拦截器堆栈中还有其他的Interceptor,那么invocation.invoke()将调用堆栈中下一个Interceptor的执行。
2. 如果拦截器堆栈中只有Action了,那么invocation.invoke()将调用Action执行。
3.

DefaultActionInvocation部分源代码:
if (interceptors.hasNext()) {
final InterceptorMapping interceptor = (InterceptorMapping) interceptors.next();
UtilTimerStack.profile("interceptor: "+interceptor.getName(),
new UtilTimerStack.ProfilingBlock<String>() {
public String doProfiling() throws Exception {
resultCode = interceptor.getInterceptor().intercept(DefaultActionInvocation.this);//递归调用拦截器
return null;
}
});
} else {
resultCode = invokeActionOnly();
}
每个拦截器中的代码的执行顺序,在Action之前,拦截器的执行顺序与堆栈中定义的一致;而在Action和Result之后,拦截器的执行顺序与堆栈中定义的顺序相反。
Interceptor拦截类型
从上面的分析,我们知道,整个拦截器的核心部分是invocation.invoke()这个函数的调用位置。事实上,我们也正式根据这句代码的调用位置,来进行拦截类型的区分的。在Struts2中,Interceptor的拦截类型,分成以下三类:
1. before
before拦截,是指在拦截器中定义的代码,它们存在于invocation.invoke()代码执行之前。这些代码,将依照拦截器定义的顺序,顺序执行。
2. after
after拦截,是指在拦截器中定义的代码,它们存在于invocation.invoke()代码执行之后。这些代码,将一招拦截器定义的顺序,逆序执行。
PreResultListener
有的时候,before拦截和after拦截对我们来说是不够的,因为我们需要在Action执行完之后,但是还没有回到视图层之前,做一些事情。Struts2同样支持这样的拦截,这种拦截方式,是通过在拦截器中注册一个PreResultListener的接口来实现的。
如:在拦截器中使用如下代码,其中MyPreResultListener实现了PreResultListener 接口并在beforeResult方法中做了一些事情然后在拦截器类中加入action.addPreResultListener(new MyPreResultListener());
从源码中,我们可以看到,我们之前提到的Struts2的Action层的4个不同的层次,在这个方法中都有体现,他们分别是:拦截器(Interceptor)、Action、PreResultListener和Result。在这个方法中,保证了这些层次的有序调用和执行
问题
使用Struts2作为web框架,知道它的拦截器(Interceptor)机制,类似与Filter和spring的AOP,于是实现了一个为Action增加自定义前置(before)动作和后置动作(after)的拦截器(曰:WInterceptor),不过用一段时间发现,在WInterceptor的after中,对Action对象的属性修改在页面看不到,对请求对象的属性设置也无效。为什么在调用了Action之后(invokeAction())之后,request就不能使用了呢,拦截器不能改变Action的Result么?
问题的关键在于,在调用actionInvocation.invoke()的之后,不仅执行类Action,也执行类Result。因而,等退回到拦截器的调用代码时,Result已经生成,View已经确定,这时你再修改模型(Action的属性)或请求对象的属性,对视图不会有任何影响。
解决办法:
方法一:使用现成的PreResultListener监听器事件
搞清楚原因,卷起袖子干吧,只要让WInterpretor的after事件,放在Result的生成之前就行了。
看看XWork的拦截器接口注入的actionInvocation,其实就提供增加Result执行的前置监听事件-PreResultListener:
- void addPreResultListener(PreResultListener listener);
void addPreResultListener(PreResultListener listener);
因此,让拦截器实现这个接口,就可以自然实现Action执行after事件了。
方法二,实现自己的 ActionInvocation ,手动分离Action和Result的执行
本来前面的方法已经很好了,可是,可是啊,在addPreResultListener里的异常,不会被Struts的框架捕获,而且,addPreResultListener接口不能传递自己的上下文参数,难道动用ThreadLocal传参?
研究了一下XWork的ActionInvocation 接口默认实现类DefaultActionInvocation, 写了一个包装类,将Action的执行和Result的生成完全分开,或许有人用的着,放上来,见附件(ActionInvocationWrapper),如有不妥之处请告知。
exeucteAction是执行Action,executeResult是执行Result
struts2 拦截器和actioninvocation、PreResultListener的更多相关文章
- Struts2拦截器原理以及实例
一.Struts2拦截器定义 1. Struts2拦截器是在访问某个Action或Action的某个方法,字段之前或之后实施拦截,并且Struts2拦截器是可插拔的,拦截器是AOP的一种实现. 2. ...
- 转载 - Struts2 拦截器详细配置过程
出处:http://www.blogjava.net/zzzlyr/archive/2009/10/12/297998.html Struts2 拦截器详细配置过程 1:所有拦截器的超级接口Inter ...
- 深入分析JavaWeb Item47 -- Struts2拦截器与文件上传下载
一.struts2中的拦截器(框架功能核心) 1.过滤器VS拦截器 过滤器VS拦截器功能是一回事. 过滤器是Servlet规范中的技术,能够对请求和响应进行过滤. 拦截器是Struts2框架中的技术. ...
- Struts2 拦截器配置以及实现
@(Java ThirdParty)[Struts|Interceptor] Struts2 拦截器配置以及实现 Struts2的拦截器应用于Action,可以在执行Action的方法之前,之后或者两 ...
- Struts2拦截器的使用 (详解)
Struts2拦截器的使用 (详解) 如何使用struts2拦截器,或者自定义拦截器.特别注意,在使用拦截器的时候,在Action里面必须最后一定要引用struts2自带的拦截器缺省堆栈default ...
- struts2拦截器
一.自定义拦截器 struts2拦截器类似于servlet过滤器 首先定义一个拦截器这个拦截器实现了Interceptor接口: package cn.orlion.interceptor; impo ...
- Struts2拦截器初涉
Struts2拦截器初涉 正在练习struts,本例是从一个pdf上摘抄的例子,那本pdf都不知道叫什么名字,不过感觉很适合初学者. 在这里要实现一个简单的拦截器"GreetingInter ...
- 浅谈Struts2拦截器的原理与实现
拦截器与过滤器 拦截器是对调用的Action起作用,它提供了一种机制可以使开发者定义在一个action执行的前后执行的代码,也可以在一个action执行前阻止其执行.同时也是提供了 ...
- struts2—拦截器
在Struts2中,如果用户没有指定执行哪些拦截器,struts2有一个默认执行的栈,defaultStack; 一旦如果用户有指定执行哪些拦截器,默认的拦截器栈就不会被执行 拦截器配置举例(stru ...
随机推荐
- java-Date、String、Calendar转化
1.Calendar 转化 String //获取当前时间的具体情况,如年,月,日,week,date,分,秒等 Calendar calendat = Calendar.getInstance(); ...
- 控件(按钮类): ButtonBase, Button, HyperlinkButton, RepeatButton, ToggleButton, AppBarButton, AppBarToggleButton
介绍背水一战 Windows 10 之 控件(按钮类) ButtonBase Button HyperlinkButton RepeatButton ToggleButton AppBarButton ...
- Servlet 工作原理解析
转自:http://www.ibm.com/developerworks/cn/java/j-lo-servlet/ Web 技术成为当今主流的互联网 Web 应用技术之一,而 Servlet 是 J ...
- 【Codeforces 707B】Bakery 水题
对每个storages找一下最短的相邻边 #include <cstdio> #define N 100005 #define inf 0x3f3f3f3f using namespace ...
- 由多线程引起的map取值为null的分析
昨天写了一个多线程的程序,却发现了一个很奇特的问题,就是我的map对象明明put了,可是get的时候竟然会取到null,而且尝试多次,有时候成功,有时候取到null,并不确定. 程序代码如下: pub ...
- 【BZOJ-4173】数学 欧拉函数 + 关于余数的变换
4173: 数学 Time Limit: 10 Sec Memory Limit: 256 MBSubmit: 306 Solved: 163[Submit][Status][Discuss] D ...
- Jenkins 1.x权限配置(兼容2.x)
说明: 1.x版本的jenkins默认是没有任何权限限制,任何人都可以访问. 需要用到的插件: [Role-based Authorization Strategy] 具体配置: 0.设置Jenkin ...
- bios中只有windows boot manager下用U盘启动
在重装系统的时候,很多时候都是先进入bios设置成U盘启动项,然后进行安装,如果年代久远一点的,就设置成光驱启动,再进行:随着时间的推行,光驱已经开始淘汰了,也怀念以前的光驱装机的时光!-:) 开始进 ...
- poj3484 Showstopper 二分
题目地址 二分用的很是巧妙!关键是抽象出问题本质. #include <cstdio> #include <string> #include <cstring> ; ...
- 数据结构作业——N!的位数(斯特灵公式)
Description 求N!的位数 Input 输入第一行为一个正整数 n(1<=n<=25000). Output 输出 n!的位数. Sample Input 1020 Sample ...