[TOC]
前语
在研究阻拦器源码的时候看到一篇百万阅读的文章,看完源码发现这篇文章有个点不太对。

比如
创建2个阻拦器,按次序添加进阻拦链中。
public class FirstInterceptor extends HandlerInterceptorAdapter {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println("FirstInterceptor 履行 preHandle--------------------");
return true;
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
System.out.println("FirstInterceptor 履行 postHandle--------------------");
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
System.out.println("FirstInterceptor 履行 afterCompletion--------------------");
}
}
public class SecondInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println("SecondInterceptor 履行 preHandle--------------------");
return true;
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
System.out.println("SecondInterceptor 履行 postHandle--------------------");
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
System.out.println("SecondInterceptor 履行 afterCompletion--------------------");
}
}
添加进链:
@Configuration
public class WebConfiguer extends WebMvcConfigurationSupport {
@Override
protected void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new FirstInterceptor());
registry.addInterceptor(new SecondInterceptor());
}
}
随意写一个接口进行调用,检查日志:

能够归纳为先进后出的策略。 先进指的是preHandle按阻拦器次序履行,其他按倒序履行。
为什么?
通过debug之后找到了源码履行的当地。

preHandle的履行
源码中是先调用applyPreHandle()办法,履行阻拦器的前置阻拦,再看下前置怎样处理的。

呐呐,源码就在这儿写着了,最初那篇文章怎样说的
回来false不会触发afterCompletion。
现在看这是不完全对的。为什么呢? 在某些条件下确实是履行不了afterCompletion的,这儿要留意后边一段代码。
this.interceptorIndex = i
这儿将已经履行的过方位赋值给了这个变量,这个变量实践上是会影响afterCompletion的履行。
后边看afterCompletion的完结时我们再讲。
postHandle的履行
能够看到源码中第三个框的当地,这儿便是后置阻拦postHandle的履行方位。

* DispatcherServlet processes a handler in an execution chain, consisting
* of any number of interceptors, with the handler itself at the end.
* With this method, each interceptor can post-process an execution,
* getting applied in inverse order of the execution chain
default void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
@Nullable ModelAndView modelAndView) throws Exception {
}
翻译之后也只是说使用这个办法能够进行后处理,以履行链相反的次序履行,并没有解说说为什么这样设计,大家有兴趣能够继续深挖一下。
afterCompletion的履行
现在我们知道了前置和后置是怎样履行的了,那么afterCompletion在什么时候调用呢?
仔细一下看源码图其实能够看到最终一个红框的当地,在这儿便是afterCompletion履行的方位。


在前面preHandle的时候我们留意到了这个变量,它决议afterCompletion能不能运行。
正常情况下,所有的阻拦器都运行了preHandle那么这儿的变量便是最终一个阻拦器的方位。
假设是5个阻拦器,那么正常这个变量就为4,再依照倒序履行afterCompletion办法。
假设第一个阻拦器的preHandle成功,第二个回来false了,那么这儿仍是能履行第一个阻拦器的afterCompletion办法的。
所以说上面那篇百万阅读的文章不完全正确,有兴趣能够自己验证一下,这儿我贴一下我验证的结果:

总结
阻拦器是spring提供的一种关于恳求的前后及完结状况的钩子,用于开发自定义处理。
它有3个常用的钩子,分别是:
- preHandle:恳求处理之前的钩子,按阻拦器次序履行。
- postHandle:恳求完结之后的钩子,按阻拦器倒序履行。
- afterCompletion:原本用于视图烘托之后调用的,现在来说用于恳求不管是否反常后的清场工作。,倒序履行。
留意:preHandle并不是回来false就一定不会触发afterCompletion钩子。
preHandle成功了几个就必然会履行几个afterCompletion,假如存在必需要履行的afterComletion办法的话一定要保证它前面和自己的阻拦器成功履行。
ps:看啥文章都不如自己实践走一遍来的好,假如有协助还请三连。。。