SpringBoot源码系列(8):拦截器执行顺序

布鸽不鸽 Lv4

前言

在SpringBoot/SpringMVC中,拦截器有三个方法

  • applyPreHandle(前置操作,目标方法执行前)
  • applyPostHandle(后置操作,目标方法执行后)
  • triggerAfterCompletion(最终操作,渲染结束后)

正常情况下,会顺序执行所有前置操作,逆序执行所有后置操作,逆序执行所有最终操作

如果中间被拦截,会顺序执行所有前置操作,直至被拦截,逆序执行所有放行的后置操作

我们根据源码来看一看其中的原理

原文地址:https://xuedongyun.cn/post/5855/

拦截器原理

DispatcherServlet

我知道,请求的核心函数是DispatcherServlet中的doDispatch方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
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拦截器链

1
2
3
4
5
6
7
8
mappedHandler = {HandlerExecutionChain}
handler = {HandlerMethod}
interceptorList = {ArrayList} size = 3
0={Onelnterceptor}
1={Twolnterceptor}
2={Threelnterceptor}
3={ConversionServiceExposinglnterceptor}
4={ResourceUrlProviderExposinglnterceptor}
  1. applyPreHandle(前置处理):可以看到,顺序执行了所有拦截器的前置操作。每次都记录了this.interceptorIndex。如果中间有返回false的,则立刻执行triggerAfterCompletion方法。
1
2
3
4
5
6
7
8
9
10
11
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开始逆序执行了所有的后置操作

1
2
3
4
5
6
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);
}
}
  1. applyPostHandle(后置处理):可以看到,逆序执行了所有后置操作
1
2
3
4
5
6
7
8
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);
}
}
  1. processDispatchResult(渲染页面):可以看到,渲染完成后,逆序执行了所有的最终操作
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
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);
}
}
1
2
3
4
5
6
7
8
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);
}
}
  • 标题: SpringBoot源码系列(8):拦截器执行顺序
  • 作者: 布鸽不鸽
  • 创建于 : 2023-06-09 14:18:34
  • 更新于 : 2023-06-25 22:56:18
  • 链接: https://xuedongyun.cn//post/5855/
  • 版权声明: 本文章采用 CC BY-NC-SA 4.0 进行许可。
评论
目录
SpringBoot源码系列(8):拦截器执行顺序