您的位置:首页 > 编程语言 > Java开发

struts2 拦截器和actioninvocation

2020-08-25 22:53 281 查看

一、Interceptor说明

  Interceptor的接口定义没有什么特别的地方,除了init和destory方法以外,intercept方法是实现整个拦截器机制的核心方法。而它所依赖的参数ActionInvocation则是我们之前章节中曾经提到过的著名的Action调度者。

  在这里需要指出的是一个很重要的方法invocation.invoke()。这是ActionInvocation中的方法,而ActionInvocation是Action调度者,所以这个方法具备以下2层含义(详细看DefaultActionInvocation源代码): 
  1、 如果拦截器堆栈中还有其他的Interceptor,那么invocation.invoke()将调用堆栈中下一个Interceptor的执行。 
  2、 如果拦截器堆栈中只有Action了,那么invocation.invoke()将调用Action执行。

 流程结构图:

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拦截类型 

二、Interceptor拦截类型

  从上面的分析,我们知道,整个拦截器的核心部分是invocation.invoke()这个函数的调用位置。事实上,我们也正式根据这句代码的调用位置,来进行拦截类型的区分的。在Struts2中,Interceptor的拦截类型,分成以下三类: 
  1、 before 
  before拦截,是指在拦截器中定义的代码,它们存在于invocation.invoke()代码执行之前。这些代码,将依照拦截器定义的顺序,顺序执行。 
  2、 after 
  after拦截,是指在拦截器中定义的代码,它们存在于invocation.invoke()代码执行之后。这些代码,将一招拦截器定义的顺序,逆序执行。

  3、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);

  因此,让拦截器实现这个接口,就可以自然实现Action执行after事件了。

  方法二:实现自己的 ActionInvocation ,手动分离Action和Result的执行

  本来前面的方法已经很好了,可是在addPreResultListener里的异常,不会被Struts的框架捕获,而且addPreResultListener接口不能传递自己的上下文参数,难道动用ThreadLocal传参?研究了一下XWork的ActionInvocation 接口默认实现类DefaultActionInvocation,可以 写了一个包装类,将Action的执行和Result的生成完全分开。exeucteAction是执行Action,executeResult是执行Result。

 

转载于https://www.geek-share.com/detail/2690656559.html

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: