前言
最近老大让每周写一篇技术性的博客,想想也没啥写,就想着随便拿个以前的项目去研究研究五大框架的底层代码。本人水平有限,有不对的地方还望大家勿喷,指正!
开始之前先了解下strtus2的工作流程:
工作原理图:
(1) 客户端(Client)向Action发用一个请求(Request)
(2) Container通过web.xml映射请求,并获得控制器(Controller)的名字
(3) 容器(Container)调用控制器(StrutsPrepareAndExecuteFilter或FilterDispatcher)。在Struts2.1以前调用FilterDispatcher,Struts2.1以后调用StrutsPrepareAndExecuteFilter
(4) 控制器(Controller)通过ActionMapper获得Action的信息
(5) 控制器(Controller)调用ActionProxy
(6) ActionProxy读取struts.xml文件获取action和interceptor stack的信息。
(7) ActionProxy把request请求传递给ActionInvocation
(8) ActionInvocation依次调用action和interceptor
(9) 根据action的配置信息,产生result
(10) Result信息返回给ActionInvocation
(11) 产生一个HttpServletResponse响应
(12) 产生的响应行为发送给客服端。
拦截器所涉及的接口和类:
用struts2实现拦截器有三种方式:
1.实现Interceptor接口
public interface Interceptor
extends Serializable
//继承Serializable
{
public abstract void destroy();
public abstract void init();
//ActionInvocation 是一个接口
public abstract String intercept(ActionInvocation actioninvocation)
throws Exception;
}
2.继承AbstractInterceptor类
public abstract class AbstractInterceptor
implements Interceptor
//并没有具体实现
{
public AbstractInterceptor()
{
}
public void init()
{
}
public void destroy()
{
}
public abstract String intercept(ActionInvocation actioninvocation)
throws Exception;
}
所以我们并不建议用上面那两种方法
- 继承MethodFilterInterceptor类
public abstract class MethodFilterInterceptor extends AbstractInterceptor { public MethodFilterInterceptor() { log = LoggerFactory.getLogger(getClass()); excludeMethods = Collections.emptySet(); includeMethods = Collections.emptySet(); } public void setExcludeMethods(String excludeMethods) { this.excludeMethods = TextParseUtil.commaDelimitedStringToSet(excludeMethods); } public Set getExcludeMethodsSet() { return excludeMethods; } public void setIncludeMethods(String includeMethods) { this.includeMethods = TextParseUtil.commaDelimitedStringToSet(includeMethods); } public Set getIncludeMethodsSet() { return includeMethods; } public String intercept(ActionInvocation invocation) throws Exception { if(applyInterceptor(invocation)) return doIntercept(invocation); else return invocation.invoke(); } protected boolean applyInterceptor(ActionInvocation invocation) { //ActionInvocation将Web页面中的输入元素封装为一个(请求)数据对象”,这个对象就是ActionInvocation类型. String method = invocation.getProxy().getMethod(); boolean applyMethod = MethodFilterInterceptorUtil.applyMethod(excludeMethods, includeMethods, method); if(log.isDebugEnabled() && !applyMethod) log.debug((new StringBuilder()).append("Skipping Interceptor... Method [").append(method).append("] found in exclude list.").toString(), new String[0]); return applyMethod; } protected abstract String doIntercept(ActionInvocation actioninvocation) throws Exception; protected transient Logger log; //排除的方法集合 protected Set excludeMethods; //包括的方法集合(就是要拦截的方法) protected Set includeMethods; }
如上图:
在执行Action的前后都有拦截器的执行,每个拦截器类的doIntercept(ActionInvocation actionInvocation)方法都会传入一个参数ActionInvocation actionInvocation并且最后一句代码都是return invocation.invoke(),这句代码调用的是DefaultActionInvocation类的invoke方法,而在这个方法里面又会去调用其他的拦截器,这样的话就形成了一个类似递归的递归调用。
上面的这两张图说明了用拦截器时配置文件的基本配法。
下面用debug的方式跟下代码:
总结
Struts2拦截器执行机理如下:
- 整个结构就如同一个堆栈,除了Action以外,堆栈中的其他元素是Interceptor
- Action位于堆栈的底部。由于堆栈"先进后出"的特性,如果我们试图把Action拿出来执行,我们必须首先把位于Action上端的Interceptor拿出来执行。这样,整个执行就形成了一个递归调用
- 每个位于堆栈中的Interceptor,除了需要完成它自身的逻辑,还需要完成一个特殊的执行职责。这个执行职责有3种选择:
1) 中止整个执行,直接返回一个字符串作为resultCode
2) 通过递归调用负责调用堆栈中下一个Interceptor的执行
3) 如果在堆栈内已经不存在任何的Interceptor,调用Action
原文地址:https://www.cnblogs.com/nnxud/p/8998008.html