准备知识
struts2作为一优秀的Web层框架,其拦截器机制更是让其如虎添翼,下面将详细介绍struts2内置的defaultStack中的18拦截工作原理其及功能。但讲解之前必须先了解struts2中拦截器的执行流程,以更好地理解各个拦截器的执行与功能。
struts2中拦截器与Action的执行调度即执行流程或者说执行顺序是由ActionInvocation来完成的(如果此处不怎么了解可以参看struts2处理请求流程详解),ActionInvocation是一接口,struts2其默认实现类是DefaultActionInvocation,拦截器与Action的执行调度就是由该完成,调度逻辑就在该类的invoke方法中,下面是invoke方法核心源码:
public String invoke() throws Exception {
//上面省略很多代码...
//判断是否有下一个拦截器
if (interceptors.hasNext()) {
final InterceptorMapping interceptor = (InterceptorMapping) interceptors.next();//获取拦截器配置
String interceptorMsg = "interceptor: " + interceptor.getName();
UtilTimerStack.push(interceptorMsg);
try {
//执行拦截器的intercept方法
resultCode = interceptor.getInterceptor().intercept(DefaultActionInvocation.this);
}
finally {
UtilTimerStack.pop(interceptorMsg);
}
} else {
//执行Action
resultCode = invokeActionOnly();
}
//下面省略很多代码
return resultCode;
}
finally {
UtilTimerStack.pop(profileKey);
}
}
在DefaultActionInvocation的init方法中完成了对当前正在执行的Action所应用上的拦截器的配置信息,放置在一个名为interceptors的List当中,通过配置信息就能获取相应的拦截器实例并执行其intercept方法,并且把ActionInvocation自已作为输入参数传递进了拦截器的intercept方法,如果在拦截器的intercept方法中又调用了ActionInvocation的invoke方法则又会再次进入invoke方法,只不过这次执行的拦截器是下一个拦截器,依此类推,假设所有拦截器都调用了ActionInvocation的invoke方法,则会把Action所应用上的所有拦截器执行一遍,如果所有拦截器都已执行完成即没有下一个拦截器了,则 if (interceptors.hasNext()) 该if条件不成立就会执行invokeActionOnly()方法,执行完Action各个拦截器依次返回,需要注意的是返回的顺序与执行的顺序刚好相反,后执行的拦截器先执行完成返回,这一点非常重要,这与Filter的执行机制是很类似的。所有拦截执行返回后得到一个resultCode去寻找相应的Result进行执行,生成页面。
struts2中所有的拦截器都要实现Interceptor接口,下面看一个其接口声明:
public interface Interceptor extends Serializable {
void destroy();
void init();
String intercept(ActionInvocation invocation) throws Exception;
}
其中就三个方法,destroy在拦截器销毁的时候会执行,init方法会在拦截器实例化完成后立即执行,最重要的是intercept方法,该方法中执行的逻辑直接影响到整个拦截器的执行流程,如果intercept方法中调用了invocation.invoke()方法则会执行下一个拦截器,如果没有调用而直接返回一个字符串则后面的所有拦截器都不会执行,更不会执行Action,然后该拦截器与前面的拦截器执行返回。
拦截器与Action的执行调度是非常重要的,只有理解了这一点才能更好的理解拦截器的工作原理。