sturts2拦截器执行顺序理解以及拦截器机制实现原理

<?xml version="1.0" encoding="GBK"?>
<!DOCTYPE struts PUBLIC
	"-//Apache Software Foundation//DTD Struts Configuration 2.1.7//EN"
	"http://struts.apache.org/dtds/struts-2.1.7.dtd">
<struts>
	<!-- 通过常量配置Struts 2的国际化资源信息 -->
	<constant name="struts.custom.i18n.resources" value="mess"/>
	<!-- 通过常量配置Struts 2所使用的解码集-->
	<constant name="struts.i18n.encoding" value="GBK"/>
	<!-- 配置本系统所使用的包 -->
	<package name="lee" extends="struts-default">
		<!-- 应用所需使用的拦截器都在该元素下配置 -->
		<interceptors>
			<!-- 配置mysimple拦截器 -->
			<interceptor name="mysimple"
			class="org.crazyit.app.interceptor.SimpleInterceptor">
				<!-- 为拦截器指定参数值 -->
				<param name="name">简单拦截器</param>
			</interceptor>
		</interceptors>

		<action name="loginPro" class="org.crazyit.app.action.LoginAction">
			<result name="error">/WEB-INF/content/error.jsp</result>
			<result name="success">/WEB-INF/content/welcome.jsp</result> 
			<!-- 配置系统的默认拦截器 -->
			<interceptor-ref name="defaultStack"/>
			<!-- 应用自定义的mysimple拦截器 -->
			<interceptor-ref name="mysimple">
				<param name="name">第一个</param>
			</interceptor-ref>
			<interceptor-ref name="mysimple">
				<param name="name">第二个</param>
			</interceptor-ref>
		</action>
		<action name="*">
			<result>/WEB-INF/content/{1}.jsp</result>
		</action>
	</package>
</struts>


自定义实现的拦截器类:

package org.crazyit.app.interceptor;

import com.opensymphony.xwork2.ActionInvocation;
import com.opensymphony.xwork2.interceptor.AbstractInterceptor;
import java.util.*;

import org.crazyit.app.action.*;
/**
 * Description:
 * <br/>网站: <a href="http://www.crazyit.org">疯狂Java联盟</a> 
 * <br/>Copyright (C), 2001-2012, Yeeku.H.Lee
 * <br/>This program is protected by copyright laws.
 * <br/>Program Name:
 * <br/>Date:
 * @author  Yeeku.H.Lee kongyeeku@163.com
 * @version  1.0
 */
public class SimpleInterceptor
	extends AbstractInterceptor
{
	//简单拦截器的名字
	private String name;
	//为该简单拦截器设置名字的setter方法
	public void setName(String name)
	{
		this.name = name;
	}
	public String intercept(ActionInvocation invocation)
		throws Exception
	{
		//取得被拦截的Action实例
		LoginAction action = (LoginAction)invocation.getAction();
		//打印执行开始的实现
		System.out.println(name + " 拦截器的动作---------" + 
			"开始执行登录Action的时间为:" + new Date());
		//取得开始执行Action的时间
		long start = System.currentTimeMillis();
		//执行该拦截器的后一个拦截器
		//如果该拦截器后没有其他拦截器,则直接执行Action的execute方法
		String result = invocation.invoke();
		//打印执行结束的时间
		System.out.println(name + " 拦截器的动作---------" + 
			"执行完登录Action的时间为:" + new Date());
		long end = System.currentTimeMillis();
		System.out.println(name + " 拦截器的动作---------" + 
			"执行完该Action的事件为" + (end - start) + "毫秒");
		return result;
	}
}

访问action结果--执行结果:



分析结果:(上面配置了2个拦截器)

      结果小猜想其中的内部机制:

              拦截前的操作:

              struts2中的filter的StrutsPrepareAndExecuteFilter控制器会拦截用户请求的action,该filter会先先查看配置文件,发现有2个拦截器,从第一个拦截器开始,通过反射生成一个SimpleInterceptor对象,然后调用其intercept()方法,执行该方法中的invocation.invoke()方法,然后该invoke方法会通过interceptors.hasNext去检查是否还有后面的拦截器,于是发现还有第二个拦截器,继续通过反射生成第二个SimpleInterceptor对象,然后再intercept()→invocation.invoke()方法→intercept()→invoke()→递归检查,直到所有拦截器都递归完毕。因此会看到控制台有从第一个拦截器→第二个拦截器。

           拦截后操作:

           因此intercept()→invocation.invoke()方法→intercept()→invoke()→方法是递归实现,也就是栈结构,先进后出,因此当invoke方法执行完后,会按照这个栈结构继续运行,从而出现了拦截后先看到第二个拦截器→第一个拦截器。

       进一步思考:

       struts2中的filter的StrutsPrepareAndExecuteFilter控制器会拦截用户请求的action,该fiter会通过查看看action的配置文件,然后生成该action对应的拦截器Map或者List来保存所配置的拦截器的相关信息。同时也会产生一个ActionInvocation对象来控制action。其中这种控制就包刮拦截,然后调用ActionInvocation对象中的invoke()方法。通过查看实现了ActionInvocation类的代码中的invoke()方法,可以知道该invoke()方法是个递归方法。因此上面两个拦截前后的操作,应该只是在invoke()方法中完成,一直递归而已。其实这种递归是这样的invoke()→→intercept()→→invoke()→→如此循环。要知道ActionInvocation是控制action的,类似与jdk的动态代理(AOP思想),将拦截器的相关方法横切到相应的action,使各自的任务达到分离!

以上猜想再看下源代码果真是这样的:

DefaultActionInvocation:该类实现了ActionInvacation

public String invoke() throws Exception {
        String profileKey = "invoke: ";
        try {
            UtilTimerStack.push(profileKey);

            if (executed) {
                throw new IllegalStateException("Action has already executed");
            }

            if (interceptors.hasNext()) {
                final InterceptorMapping interceptor = interceptors.next();
                String interceptorMsg = "interceptor: " + interceptor.getName();
                UtilTimerStack.push(interceptorMsg);
                try {
                                resultCode = interceptor.getInterceptor().intercept(DefaultActionInvocation.this);
                            }
                finally {
                    UtilTimerStack.pop(interceptorMsg);
                }
            } else {
                resultCode = invokeActionOnly();
            }

            // this is needed because the result will be executed, then control will return to the Interceptor, which will
            // return above and flow through again
            if (!executed) {
                if (preResultListeners != null) {
                    for (Object preResultListener : preResultListeners) {
                        PreResultListener listener = (PreResultListener) preResultListener;

                        String _profileKey = "preResultListener: ";
                        try {
                            UtilTimerStack.push(_profileKey);
                            listener.beforeResult(this, resultCode);
                        }
                        finally {
                            UtilTimerStack.pop(_profileKey);
                        }
                    }
                }

                // now execute the result, if we're supposed to
                if (proxy.getExecuteResult()) {
                    executeResult();
                }

                executed = true;
            }

            return resultCode;
        }
        finally {
            UtilTimerStack.pop(profileKey);
        }
    }


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值