前言
在SpringBoot/SpringMVC中,拦截器有三个方法
applyPreHandle
(前置操作,目标方法执行前)applyPostHandle
(后置操作,目标方法执行后)triggerAfterCompletion
(最终操作,渲染结束后)
正常情况下,会顺序执行所有前置操作,逆序执行所有后置操作,逆序执行所有最终操作。
如果中间被拦截,会顺序执行所有前置操作,直至被拦截,逆序执行所有放行的后置操作。
我们根据源码来看一看其中的原理
原文地址:https://xuedongyun.cn/post/5855/
拦截器原理
DispatcherServlet
我知道,请求的核心函数是DispatcherServlet
中的doDispatch
方法
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
try {
mappedHandler = getHandler(processedRequest);
HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
// 前置处理
if (!mappedHandler.applyPreHandle(processedRequest, response)) {
return;
}
// 执行目标方法
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
// 后置处理
mappedHandler.applyPostHandle(processedRequest, response, mv);
// 渲染页面
processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
} catch (Exception ex) {
// 有任何错误,都会触发后置处理
triggerAfterCompletion(processedRequest, response, mappedHandler, ex);
}
}
目标方法出错,也会执行后置操作
HandlerExecutionChain
mappedHandler
中包含:handler
和拦截器链
mappedHandler = {HandlerExecutionChain}
handler = {HandlerMethod}
interceptorList = {ArrayList} size = 3
0={Onelnterceptor}
1={Twolnterceptor}
2={Threelnterceptor}
3={ConversionServiceExposinglnterceptor}
4={ResourceUrlProviderExposinglnterceptor}
applyPreHandle
(前置处理):可以看到,顺序执行了所有拦截器的前置操作。每次都记录了this.interceptorIndex
。如果中间有返回false
的,则立刻执行triggerAfterCompletion
方法。
boolean applyPreHandle(HttpServletRequest request, HttpServletResponse response) throws Exception {
for (int i = 0; i < this.interceptorList.size(); i++) {
HandlerInterceptor interceptor = this.interceptorList.get(i);
if (!interceptor.preHandle(request, response, this.handler)) {
triggerAfterCompletion(request, response, null);
return false;
}
this.interceptorIndex = i;
}
return true;
}
而triggerAfterCompletion
则是从this.interceptorIndex
开始逆序执行了所有的后置操作
void triggerAfterCompletion(HttpServletRequest request, HttpServletResponse response, @Nullable Exception ex) {
for (int i = this.interceptorIndex; i >= 0; i--) {
HandlerInterceptor interceptor = this.interceptorList.get(i);
interceptor.afterCompletion(request, response, this.handler, ex);
}
}
applyPostHandle
(后置处理):可以看到,逆序执行了所有后置操作
void applyPostHandle(HttpServletRequest request, HttpServletResponse response, @Nullable ModelAndView mv)
throws Exception {
for (int i = this.interceptorList.size() - 1; i >= 0; i--) {
HandlerInterceptor interceptor = this.interceptorList.get(i);
interceptor.postHandle(request, response, this.handler, mv);
}
}
processDispatchResult
(渲染页面):可以看到,渲染完成后,逆序执行了所有的最终操作
private void processDispatchResult(HttpServletRequest request, HttpServletResponse response,
@Nullable HandlerExecutionChain mappedHandler,
@Nullable ModelAndView mv,
@Nullable Exception exception) throws Exception {
if (mv != null && !mv.wasCleared()) {
render(mv, request, response);
if (errorView) {
WebUtils.clearErrorRequestAttributes(request);
}
}
if (mappedHandler != null) {
// 页面渲染完,逆序触发拦截器
mappedHandler.triggerAfterCompletion(request, response, null);
}
}
void triggerAfterCompletion(HttpServletRequest request,
HttpServletResponse response,
@Nullable Exception ex) {
for (int i = this.interceptorIndex; i >= 0; i--) {
HandlerInterceptor interceptor = this.interceptorList.get(i);
interceptor.afterCompletion(request, response, this.handler, ex);
}
}