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个逐步迭代到最后一个。

时间: 2024-10-07 17:01:45

Struts2系列:(16)Interceptor组成的链是如何进行调用的的相关文章

Struts2系列:(7)通配符和动态方法调用

当前存在的问题:在struts.xml配置文件中,每个action标签对应一个类中的方法.但是,在实际JavaWeb项目开发中,有许多继承自ActionSupport类的类(其中也包括很多方法),如果每个方法对应一个action标签,那么就会造成struts.xml非常庞大. 本节中介绍的通配符 和 动态方法调用 就是为了解决这一问题.本节分成2个部分:(1)通配符映射 和 (2)动态调用 概念:Struts应用可能有很多action 声明,可把多个相似的映射关系简化为一个(通用)映射关系的机制

struts2.3.16中表单重复提交出现空指针异常

异常代码形式: 严重: Exception occurred during processing request: nulljava.lang.NullPointerException    at com.opensymphony.xwork2.util.LocalizedTextUtil.findText(LocalizedTextUtil.java:630)    at com.opensymphony.xwork2.util.LocalizedTextUtil.findText(Local

[转]Struts2.3.16.1+Hibernate4.3.4+Spring4.0.2 框架整合

原文地址:http://blog.csdn.net/ycb1689/article/details/22928519 最新版Struts2+Hibernate+Spring整合 目前为止三大框架最新版本是: struts2.3.16.1 hibernate4.3.4 spring4.0.2 其中struts2和hibernate的下载方式比较简单,但是spring下载有点麻烦,可以直接复制下面链接下载最新版spring http://repo.springsource.org/libs-rele

Struts2.3.16.1+Hibernate4.3.4+Spring4.0.2 框架整合

最新版Struts2+Hibernate+Spring整合 目前为止三大框架最新版本是: struts2.3.16.1 hibernate4.3.4 spring4.0.2 其中struts2和hibernate的下载方式比较简单,但是spring下载有点麻烦,可以直接复制下面链接下载最新版spring http://repo.springsource.org/libs-release-local/org/springframework/spring/4.0.2.RELEASE/spring-f

[Android学习系列16]Android把php输出的json加载到listview

首先写个php脚本输出json,注意,还要输出回车,方便android的bufferreader读取一行 <?php class Book { public $bookid; public $bookname; public $bookinfo; function __construct($id,$name,$info ){ $this->bookid = $id; $this->bookname = $name; $this->bookinfo = $info; } } $boo

Struts2 filter vs interceptor vs listener 抄来的!!!

过滤器,是在java web中,你传入的request,response提前过滤掉一些信息,或者提前设置一些参数,然后再传入servlet或者struts2的action进行业务逻辑,比如过滤掉非法url(不是login.do的地址请求,如果用户没有登陆都过滤掉),或者在传入servlet或者 struts2的action前统一设置字符集,或者去除掉一些非法字符 拦截器,是在面向切面编程的就是在你的service或者一个方法,前调用一个方法,或者在方法后调用一个方法比如动态代理就是拦截器的简单实

struts2.3.16所需的基本的jar包---------SSH升级包不是整体全部都升级的

struts2.3.16所需的基本的jar包 jar包放多了就报Exception什么Unable to load....上网搜了半天也没有能解决的 下面所说的jar包放到WEB-INF/lib以及tomcat/lib中 通过我一个一个添加到tomcat/lib中,直到启动服务器的时候不再报ClassNotFoundException或者ClassDefNotFoundException为止,真TM不容易啊 commons-fileupload-1.3.1.jar commons-io-2.2.

struts2.3.16所需的基本的jar包

jar包放多了就报Exception什么Unable to load....上网搜了半天也没有能解决的 下面所说的jar包放到WEB-INF/lib以及tomcat/lib中 通过我一个一个添加到tomcat/lib中,直到启动服务器的时候不再报ClassNotFoundException或者ClassDefNotFoundException为止,真TM不容易啊 commons-fileupload-1.3.1.jar commons-io-2.2.jar commons-lang3-3.1.j

EMVTag系列16——AC响应数据

在一个联机交易中,要传送到发卡行的专有应用数据. 字段 长度(字节) 赋值 说明 长度 1 07 分散密钥索引 1 00 密文版本号 1 01 根据发卡行密钥版本设置 卡片验证结果(CVR) 4 03 00 bits 8–7: 00 = 第2个GENERATE AC返回AAC 01 = 第2个GENERATE AC返回TC 10 = 不请求第2个GENERATE AC 11 = RFU bits 6–5: 00 = 第1个GENERATE AC返回AAC 01 = 第1个GENERATE AC返