在项目中,存在需求需要统一对代码进行做拦截处理,比如:日志记录,xss处理,全局异常处理等。实现拦截功能的方式也很多,可以通过 Filter、HandlerInterceptor、ControllerAdvice、Aop 来实现。
所以了解这些实现方式之间的执行顺序,对于开发来说变得至关重要。
一、分析以上几种拦截功能的执行顺序
来看一张各拦截器执行的平面剖析图
从图中能够得出集中拦截器同时存在时各自的执行顺序,包括多个同种类型拦截器存在时各自的执行顺序。
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 。
public class DispatcherServlet extends FrameworkServlet {
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
try {
// 执行 HandlerInterceptor#preHandler
if (!mappedHandler.applyPreHandle(processedRequest, response)) {
return;
}
// 执行 AOP + controller 方法
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
// 执行 HandlerInterceptor#postHandle
mappedHandler.applyPostHandle(processedRequest, response, mv);
// 执行 ControllerAdvice 异常处理代码
processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
}
catch (Exception ex) {
// 执行 HandlerInterceptor#afterCompletion
triggerAfterCompletion(processedRequest, response, mappedHandler, ex);
}
}
}
以上源码的简单剖析能够验证,几种拦截器共存时各自的执行顺序.
1.2、代码验证拦截器执行顺序
多个 Filter 代码
多个 HnadlerInterceptor 代码
多个 ControllerAdvice 代码
多个 AOP 的执行顺序 代码
测试用的 API 代码
测试打印日志
同种拦截器的执行顺序
Filter
多个 Filter 的执行顺序在其注册时候可以指定。值越小,优先级越高。
HandlerInterceptor
多个 HandlerInterceptor ,各自的执行顺序根据在 WebMvcConfigurer#addInterceptors 设置拦截器时,先进先出,先设置的优先级高。
ControllerAdvice
结合异常处理,多个 ControllerAdvice 哪个匹配到,就那个进行处理。
AOP
多个 AOP 通过 @Order 注解进行优先级设置,数值越小越优先