前言
现在很多项目都是基于 spring boot 开发的,而且目前很多公司都做 BS,很难避免和 org.springframework.web.servlet.HandlerInterceptor
打交道。因此,我们需要了解它,以备不时之需。
HandlerInterceptor
我们做鉴权或者要对某个特定的路径要做特殊处理时,常常会实现 HandlerInterceptor 或者继承 HandlerInterceptor 的子类。HandlerInterceptor 的类图关系如下
HandlerInterceptor 定义了三个方法:
- preHandle
严谨的调用时机可以看源码或者看注释。这里简单地说 preHandle 的调用时机是在调用我们的 controller 接口前。 - postHandle
在执行完我们 controller 接口后,在渲染页面前(或者说返回 response 给调用方前)。 - afterCompletion
在完成 request 请求后会调用该方法。要注意的是:只有 preHandle 方法成功结束并且返回 true才会执行此方法。
HandlerInterceptor 的调用时机
我们都知道拦截器要在注册器上注册才会生效,但是它具体是什么时候被调用的呢?请看下图
这个流程图我省略了比较多处理逻辑,因为那些都不是这篇文章所关心的了。这里主要看
org.springframework.web.servlet.HandlerInterceptor#preHandle
和 org.springframework.web.servlet.HandlerInterceptor#afterCompletion
何时被调用;多个拦截器时,spring 是怎么处理的,用了什么设计模式,好处是什么。
源码解析
DispatcherServlet 是 spring mvc 一个很重要的类,我们的请求都是由这个调度器分配到适合的方法处理的。
找到当前请求合适的 handler 执行器后,就会执行下面这个方法
我们看下这个方法里面实际的处理逻辑
HandlerExecutionChain#applyPreHandle 返回 false 的话,那么调度器就会终止,所以当我们拦截器返回 false时,就无法请求到我们的接口。
note :显然,这里拦截器采用的是责任链设计模式。
好处如下:
- 解耦
责任链模式允许将不同的拦截逻辑分离到不同的拦截器类中。每个拦截器类只需要处理自己关注的逻辑,而不必关心其他拦截器的实现。 - 灵活配置
通过责任链模式,可以灵活地配置和管理多个拦截器的执行顺序。Spring 提供了方便的配置方式,可以根据需要增加、删除、或调整拦截器的顺序。spring 允许我们通过addPathPatterns()
为每个拦截器指定适配特定的请求路径。 - 扩展性
责任链模式使得新增或移除拦截器变得非常容易。开发者可以随时添加新的拦截器来处理新的需求,而不需要对现有的拦截器做出任何修改。 - 条件执行
一个拦截器不通过,后面的拦截器不用执行,提升性能。
afterCompletion
这里可以看到当有拦截器返回 false 时,就会调用 triggerAfterCompletion 方法,我们看下里面的代码。
拦截器是遍历执行的,第一个return true 的拦截器的 afterCompletion 最后执行。