在项目中,存在需求需要统一对代码进行做拦截处理,比如:日志记录,xss处理,全局异常处理等。实现拦截功能的方式也很多,可以通过 Filter、HandlerInterceptor、ControllerAdvice、Aop 来实现。
所以了解这些实现方式之间的执行顺序,对于开发来说变得至关重要。

一、分析以上几种拦截功能的执行顺序

来看一张各拦截器执行的平面剖析图
07-01.png

从图中能够得出集中拦截器同时存在时各自的执行顺序,包括多个同种类型拦截器存在时各自的执行顺序。

1.1、从源码层面分析各种拦截器执行顺序

在 Filter、HandlerInterceptor、ControllerAdvice、Aop 中除了 Filter 外其他的都是 Spring MVC 模块中的功能。

在 Spring MVC 中,所有请求的入口为 DispatcherServlet,而 DispatcherServlet 本身是一个 Servlet 。而 Filter 是对 Servlet 进行拦截的过滤器,
所以在这几种拦截器实现方式中 Filter 是最先被执行的。

下面通过 DispatcherServlet 源码分析各种拦截器的执行顺序

DispatcherServlet 本身就是一个Servlet ,Servlet 在处理 Request 时会调用 Servlet#service 。在 DispatcherServlet 中 DispatcherServlet#doService 会调用 DispatcherServlet#doDispatch 。

  1. public class DispatcherServlet extends FrameworkServlet {
  2. protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
  3. try {
  4. // 执行 HandlerInterceptor#preHandler
  5. if (!mappedHandler.applyPreHandle(processedRequest, response)) {
  6. return;
  7. }
  8. // 执行 AOP + controller 方法
  9. mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
  10. // 执行 HandlerInterceptor#postHandle
  11. mappedHandler.applyPostHandle(processedRequest, response, mv);
  12. // 执行 ControllerAdvice 异常处理代码
  13. processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
  14. }
  15. catch (Exception ex) {
  16. // 执行 HandlerInterceptor#afterCompletion
  17. triggerAfterCompletion(processedRequest, response, mappedHandler, ex);
  18. }
  19. }
  20. }

以上源码的简单剖析能够验证,几种拦截器共存时各自的执行顺序.

1.2、代码验证拦截器执行顺序

多个 Filter 代码

07-02.png

多个 HnadlerInterceptor 代码

07-03.png

多个 ControllerAdvice 代码

07-04.png

多个 AOP 的执行顺序 代码

07-05.png

测试用的 API 代码

07-06.png

测试打印日志

程序正常运行时
07-07.png
程序抛出异常时
07-08.png

同种拦截器的执行顺序

Filter

多个 Filter 的执行顺序在其注册时候可以指定。值越小,优先级越高。

案例如下图:
07-09.png

HandlerInterceptor

多个 HandlerInterceptor ,各自的执行顺序根据在 WebMvcConfigurer#addInterceptors 设置拦截器时,先进先出,先设置的优先级高。

案例如下图:
07-10.png

ControllerAdvice

结合异常处理,多个 ControllerAdvice 哪个匹配到,就那个进行处理。

AOP

多个 AOP 通过 @Order 注解进行优先级设置,数值越小越优先

07-11.png