Struts2系列:(16)Interceptor组成的链是如何进行调用的
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Struts2系列:(16)Interceptor组成的链是如何进行调用的相关的知识,希望对你有一定的参考价值。
首先看一下com.opensymphony.xwork2.interceptor.Interceptor的源码:
public interface Interceptor extends Serializable { /** * Called to let an interceptor clean up any resources it has allocated. */ void destroy(); /** * Called after an interceptor is created, but before any requests are processed using * {@link #intercept(com.opensymphony.xwork2.ActionInvocation) intercept} , giving * the Interceptor a chance to initialize any needed resources. */ void init(); /** * Allows the Interceptor to do some processing on the request before and/or after the rest of the processing of the * request by the {@link ActionInvocation} or to short-circuit the processing and just return a String return code. * * @param invocation the action invocation * @return the return code, either returned from {@link ActionInvocation#invoke()}, or from the interceptor itself. * @throws Exception any system-level error, as defined in {@link com.opensymphony.xwork2.Action#execute()}. */ String intercept(ActionInvocation invocation) throws Exception; }
在这里,重点关注intercept方法
String intercept(ActionInvocation invocation)
它接收一个ActionInvocation类型的参数。
接下来,进行看一下com.opensymphony.xwork2.ActionInvocation的invoke方法。
com.opensymphony.xwork2.ActionInvocation是一个接口,它提供了invoke方法的定义:
通过invoke方法的注释,可以得到:如果存在多个Interceptor,通过调用ActionInvocation对象的invoke方法,可以让下一个拦截器(Interceptor)执行。
/** * ActionInvocation代表了Action的执行状态。由ActionInvocation对象可以获取到拦截器(Interceptors)和Action实例。 * An ActionInvocation represents the execution state of an Action. It holds the Interceptors and the Action instance. * By repeated re-entrant execution of the <code>invoke()</code> method, initially by the {@link ActionProxy}, then by the Interceptors, the * Interceptors are all executed, and then the {@link Action} and the {@link Result}. * * @author Jason Carreira * @see com.opensymphony.xwork2.ActionProxy */ public interface ActionInvocation extends Serializable { /** * Invokes the next step in processing this ActionInvocation. * * If there are more Interceptors, this will call the next one. If Interceptors choose not to short-circuit * ActionInvocation processing and return their own return code, they will call invoke() to allow the next Interceptor * to execute. If there are no more Interceptors to be applied, the Action is executed. * If the {@link ActionProxy#getExecuteResult()} method returns <tt>true</tt>, the Result is also executed. * * @throws Exception can be thrown. * @return the return code. */ String invoke() throws Exception; //其它代码省略 }
在这里,只是对invoke()方法的定义和简单描述,我们需要得到更详尽的信息来知道它是如何执行的。
接下来,我们看com.opensymphony.xwork2.DefaultActionInvocation这个类,它是ActionInvocation接口的默认实现类。
在继续深入下一步的代码之前,让我们回顾一下自己的目的,我们的目的是想要知道:多个Interceptor是如何一个接一个的执行的?在Struts2的内部,一定是维护一个Interceptor的列表,然后一个接一个地执行每一个Interceptor。
接下来的代码对com.opensymphony.xwork2.DefaultActionInvocation进行简化,如下:
public class DefaultActionInvocation implements ActionInvocation { protected ActionProxy proxy; protected Iterator<InterceptorMapping> interceptors; protected String resultCode; protected void createInterceptors(ActionProxy proxy) { // get a new List so we don‘t get problems with the iterator if someone changes the list List<InterceptorMapping> interceptorList = new ArrayList<InterceptorMapping>(proxy.getConfig().getInterceptors()); interceptors = interceptorList.iterator(); } public String invoke() throws Exception { if (interceptors.hasNext()) { final InterceptorMapping interceptor = interceptors.next(); String interceptorMsg = "interceptor: " + interceptor.getName(); resultCode = interceptor.getInterceptor().intercept(DefaultActionInvocation.this); } else { resultCode = invokeActionOnly(); } return resultCode; } }
在上面的createInterceptors(ActionProxy proxy)方法中,看到下面这一行代码:
List<InterceptorMapping> interceptorList = new ArrayList<InterceptorMapping>(proxy.getConfig().getInterceptors());
我们关注new ArrayList<InterceptorMapping>后面小括号中的代码:
proxy.getConfig().getInterceptors()
我们自己重新写一下这个代码,如下:
ActionProxy proxy = invocation.getProxy();//ActionInvocation--->ActionProxy ActionConfig config = proxy.getConfig();//ActionProxy-->ActionConfig List<InterceptorMapping> interceptors = config.getInterceptors();//ActionConfig-->得到所有的拦截器
由ActionInvocation对象可以得到ActionProxy对象,再由ActionProxy对象得到ActionConfig对象,最后由ActionConfig对象得到拦截器的List列表。
接下来,我们再回到createInterceptors(ActionProxy proxy)方法内,
List<InterceptorMapping> interceptorList = new ArrayList<InterceptorMapping>(proxy.getConfig().getInterceptors()); interceptors = interceptorList.iterator();
这两句代码执行过后,interceptors是一个迭代器对象。
看完了createInterceptors(ActionProxy proxy)方法,我们再来看invoke()方法
public String invoke() throws Exception { if (interceptors.hasNext()) { final InterceptorMapping interceptor = interceptors.next(); String interceptorMsg = "interceptor: " + interceptor.getName(); resultCode = interceptor.getInterceptor().intercept(DefaultActionInvocation.this); } else { resultCode = invokeActionOnly(); } return resultCode; }
通过
interceptors.hasNext()
来查看,是否有后续的元素。如果没有后续元素,则执行
resultCode = invokeActionOnly();
也就是执行最后的action。
如果有后续元素,则通过
final InterceptorMapping interceptor = interceptors.next();
来得到下一个interceptor对象,
resultCode = interceptor.getInterceptor().intercept(DefaultActionInvocation.this);
我们再进一步拆解一下代码,就变成 如下代码:
ActionProxy proxy = invocation.getProxy();//ActionInvocation--->ActionProxy ActionConfig config = proxy.getConfig();//ActionProxy-->ActionConfig List<InterceptorMapping> interceptors = config.getInterceptors();//ActionConfig-->得到所有的拦截器 Iterator<InterceptorMapping> iterator = interceptors.iterator(); if(iterator.hasNext()) { InterceptorMapping interceptorMapping = iterator.next(); Interceptor interceptor = interceptorMapping.getInterceptor(); interceptor.intercept(invocation); }
在
resultCode = interceptor.getInterceptor().intercept(DefaultActionInvocation.this);
代码,我觉得,最精妙的的地方在于
DefaultActionInvocation.this
"类名.this",这种写法是,当内部类访问外部类的实例时所采用的写法。
在这里,它把自身作为参数传递进行,就使得所有的拦截器的intercept的方法中所接收的ActionInvocation对象是同一个对象。
正因为所有拦截器的intercept方法所接收的ActionInvocation是同一个对象,才使得所有的拦截器能够从第1个逐步迭代到最后一个。
以上是关于Struts2系列:(16)Interceptor组成的链是如何进行调用的的主要内容,如果未能解决你的问题,请参考以下文章
springBoot系列教程08:拦截器(Interceptor)的使用
struts2中啥时候使用filter啥时候使用interceptor?