您的位置:首页 > 其它

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

2013-04-01 12:26 501 查看
<?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);
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐