我们写一个拦截器之后,那拦截器是在何时执行的呢?多个拦截器之间它们的执行顺序又是怎样的?
让我们带着这些问题来看这篇文章
不知道拦截器怎么获取到的,可以看这篇文章:SpringMVC原理(2)-目标方法是怎么被找到的
HandlerInterceptor
实现一个拦截器,需要实现此接口
public interface HandlerInterceptor {
// 在目标方法执行前调用
// request对象、response对象、目标方法
default boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
return true;
}
// 在目标方法执行之后调用,但在视图渲染前调用
// request对象、response对象、目标方法、目标方法的执行结果
default void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
@Nullable ModelAndView modelAndView) throws Exception {
}
// 在请求完全处理完毕后调用
// request对象、response对象、目标方法、异常信息
default void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler,
@Nullable Exception ex) throws Exception {
}
}
核心方法:doDispatch()
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
try {
ModelAndView mv = null;
Exception dispatchException = null;
try {
// 省略代码
...
// 拦截器前置处理
if (!mappedHandler.applyPreHandle(processedRequest, response)) {
// 前置处理返回false,则终止执行(也就是拦截)
return;
}
// 执行目标方法
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
if (asyncManager.isConcurrentHandlingStarted()) {
return;
}
applyDefaultViewName(processedRequest, mv);
// 拦截器后置处理
mappedHandler.applyPostHandle(processedRequest, response, mv);
}
// 省略代码
...
// 拦截器最终处理
processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
}
catch (Exception ex) {
triggerAfterCompletion(processedRequest, response, mappedHandler, ex);
}
catch (Throwable err) {
triggerAfterCompletion(processedRequest, response, mappedHandler,
new NestedServletException("Handler processing failed", err));
}
// 省略代码
...
}
原理
// ==========================前置处理==================================
boolean applyPreHandle(HttpServletRequest request, HttpServletResponse response) throws Exception {
HandlerInterceptor[] interceptors = getInterceptors();
if (!ObjectUtils.isEmpty(interceptors)) {
// 正序遍历所有拦截器,挨个执行 preHandle() 方法
for (int i = 0; i < interceptors.length; i++) {
HandlerInterceptor interceptor = interceptors[i];
// 前置处理
if (!interceptor.preHandle(request, response, this.handler)) {
// 拦截器的最终处理
triggerAfterCompletion(request, response, null);
// 执行失败,返回false
return false;
}
// 记录执行到哪个拦截器的索引
this.interceptorIndex = i;
}
}
return true;
}
// =========================后置处理====================
void applyPostHandle(HttpServletRequest request, HttpServletResponse response, @Nullable ModelAndView mv)
throws Exception {
// 倒序遍历所有拦截器,挨个执行 postHandle()
for (int i = this.interceptorList.size() - 1; i >= 0; i--) {
HandlerInterceptor interceptor = this.interceptorList.get(i);
interceptor.postHandle(request, response, this.handler, mv);
}
}
// ==========================最终处理==================================
void triggerAfterCompletion(HttpServletRequest request, HttpServletResponse response, @Nullable Exception ex) {
// 倒序遍历已经执行过了的拦截器,挨个执行 afterCompletion()
for (int i = this.interceptorIndex; i >= 0; i--) {
HandlerInterceptor interceptor = this.interceptorList.get(i);
try {
interceptor.afterCompletion(request, response, this.handler, ex);
}
catch (Throwable ex2) {
logger.error("HandlerInterceptor.afterCompletion threw exception", ex2);
}
}
}
整个的执行流程
-
通过
HandlerMapping得到HandlerExecutionChain对象(包括处理器和拦截器链) -
拦截器的前置处理:正序遍历所有拦截器,挨个执行
preHandle()方法-
如果返回true:记录当前执行到哪个拦截器的索引,并执行下一个拦截器的
preHandle() -
如果返回false:则执行已经执行过了的拦截器的
afterCompletion(),并返回false(代表终止方法)
-
-
目标方法的执行
-
拦截器的后置处理:倒序遍历所有的拦截器,挨个执行
postHandle() -
渲染页面:
render(mv, request, response)执行完成 -
前面所有步骤如果有任何异常,都会执行拦截器的最终处理步骤
afterCompletion() -
拦截器的最终处理:拿到执行到哪个拦截器的索引,然后挨个(倒序)执行
afterCompletion()
为啥要记录拦截器的索引:执行
afterCompletion()会用到