Interceptor的接口定义没有什么特别的地方,除了init和destory方法之外,intercept方法是实现整个拦截器机制的核心方法。而它所依赖的参数ActionInvocation则是咱们以前章节中曾经提到过的著名的Action调度者。web
在这里须要指出的是一个很重要的方法invocation.invoke()。这是ActionInvocation中的方法,而ActionInvocation是Action调度者,因此这个方法具有如下2层含义(详细看DefaultActionInvocation源代码):
一、 若是拦截器堆栈中还有其余的Interceptor,那么invocation.invoke()将调用堆栈中下一个Interceptor的执行。
二、 若是拦截器堆栈中只有Action了,那么invocation.invoke()将调用Action执行。app
流程结构图:框架
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以后,拦截器的执行顺序与堆栈中定义的顺序相反。2、Interceptor拦截类型 this
从上面的分析,咱们知道,整个拦截器的核心部分是invocation.invoke()这个函数的调用位置。事实上,咱们也正式根据这句代码的调用位置,来进行拦截类型的区分的。在Struts2中,Interceptor的拦截类型,分红如下三类:
一、 before
before拦截,是指在拦截器中定义的代码,它们存在于invocation.invoke()代码执行以前。这些代码,将依照拦截器定义的顺序,顺序执行。
二、 after
after拦截,是指在拦截器中定义的代码,它们存在于invocation.invoke()代码执行以后。这些代码,将一招拦截器定义的顺序,逆序执行。spa
三、PreResultListener .net
有的时候,before拦截和after拦截对咱们来讲是不够的,由于咱们须要在Action执行完以后,可是尚未回到视图层以前,作一些事情。Struts2一样支持这样的拦截,这种拦截方式,是经过在拦截器中注册一个PreResultListener的接口来实现的。如:在拦截器中使用以下代码,其中MyPreResultListener实现了PreResultListener 接口并在beforeResult方法中作了一些事情而后在拦截器类中加入code
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么?blog
问题的关键在于,在调用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://blog.csdn.net/xuchuangqi/article/details/53248306