当一个请求到达后,会调用DispatcherServlet的doDispatch( )方法,在此方法中调用拦截器,调用方法栈如下:
doDispatch( )方法源码如下:
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
try{
HandlerExecutionChain mappedHandler = null;
...
//执行interceptor的preHandle
if (!mappedHandler.applyPreHandle(processedRequest, response)) {
return;
}
//执行实际的Controller
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
...
//执行interceptor的postHandle
mappedHandler.applyPostHandle(processedRequest, response, mv);
}catch (Exception ex) {
dispatchException = ex;
}
catch (Throwable err) {
dispatchException = new NestedServletException("Handler dispatch failed", err);
}
...
//渲染页面并执行afterCompletion
processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
...
}
HandlerExecutionChain是一个由拦截器组成的一个chain链,是一个责任链模式,内部保存了拦截器的集合,这个集合和filter过滤器一样,是在请求到来后,根据url进行正则匹配,从所有的拦截器中选出符合规则的,然后加入到集合中。
public class HandlerExecutionChain {
private final Object handler;
private HandlerInterceptor[] interceptors;
private List<HandlerInterceptor> interceptorList;
private int interceptorIndex = -1;
...
HandlerExecutionChain的applyHandle方法如下:
boolean applyPreHandle(HttpServletRequest request, HttpServletResponse response) throws Exception {
HandlerInterceptor[] interceptors = getInterceptors();
if (!ObjectUtils.isEmpty(interceptors)) {
for (int i = 0; i < interceptors.length; i++) {
HandlerInterceptor interceptor = interceptors[i];
if (!interceptor.preHandle(request, response, this.handler)) {
triggerAfterCompletion(request, response, null);
return false;
}
this.interceptorIndex = i;
}
}
return true;
}
执行逻辑是:按照拦截器的顺序从前向后执行preHandle方法,如果有一个拦截器返回了false,那么将不再继续执行当前拦截器及其之后拦截器的preHandle,而是按拦截器逆序执行afterCompletion方法:
void triggerAfterCompletion(HttpServletRequest request, HttpServletResponse response, Exception ex)
throws Exception {
HandlerInterceptor[] interceptors = getInterceptors();
if (!ObjectUtils.isEmpty(interceptors)) {
for (int i = this.interceptorIndex; i >= 0; i--) {
HandlerInterceptor interceptor = interceptors[i];
try {
interceptor.afterCompletion(request, response, this.handler, ex);
}
catch (Throwable ex2) {
logger.error("HandlerInterceptor.afterCompletion threw exception", ex2);
}
}
}
}
triggerAfterCompletion方法会吞掉所有异常,保证拦截器的afterCompletion方法全部得到执行。注意triggerAfterCompletion方法的循环边界,是 interceptorIndex,而不是 interceptors.length,也就是说只执行那些preHandle方法返回true的拦截器。之后return false。不再继续执行真正的Controller。
如果拦截器均返回了true,那么继续执行Controller的逻辑,然后按逆序执行拦截器的postHandle方法:
void applyPostHandle(HttpServletRequest request, HttpServletResponse response, ModelAndView mv) throws Exception {
HandlerInterceptor[] interceptors = getInterceptors();
if (!ObjectUtils.isEmpty(interceptors)) {
for (int i = interceptors.length - 1; i >= 0; i--) {
HandlerInterceptor interceptor = interceptors[i];
interceptor.postHandle(request, response, this.handler, mv);
}
}
}
如果在执行preHandle和postHandle时抛出了异常,那么会把异常记录下来,然后执行processDispatchResult方法;如果一切顺利,那么也会执行processDispatchResult方法:
private void processDispatchResult(HttpServletRequest request, HttpServletResponse response,
HandlerExecutionChain mappedHandler, ModelAndView mv, Exception exception) throws Exception {
boolean errorView = false;
if (exception != null) {
...
//处理错误页面
mv = processHandlerException(request, response, handler, exception);
...
}
...
//写回浏览器结果
render(mv, request, response);
...
//执行拦截器的afterCompletion方法
if (mappedHandler != null) {
mappedHandler.triggerAfterCompletion(request, response, null);
}
}
总结一下:当一个请求到达之后,springmvc会根据请求的url找出相匹配的拦截器,组装成一个责任链,按照拦截器顺序依次执行其preHandle方法,执行完毕之后,继续执行具体的Controller,当Controller执行完成后,会逆序执行拦截器的postHandle方法,之后渲染页面,最后逆序 执行afterCompletion方法。如果在执行preHandle的过程中,有任意一个interceptor返回了false,那么请求将不再继续向下执行,在逆序执行完之前返回true的拦截器的afterCompletion方法后,结束对请求的处理。如果在preHandle和postHandle方法中抛出了异常,那么spring会将异常捕捉,记录异常信息,不再继续执行拦截器的处理,而是执行渲染页面并执行那些成功执行过preHandle方法的拦截器的afterCompletion方法。