SpringBoot之拦截器(Interceptor)
前言
在使用 SpringBoot 进行 javaEE 的开发过程中,如果希望添加拦截器,一般会实现 HandlerInterceptor 接口,然后通过 SpringBoot 的机制,将拦截器作用于指定方法上
HandlerInterceptor接口
public interface HandlerInterceptor {default boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {return true;}default void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable ModelAndView modelAndView) throws Exception {}default void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable Exception ex) throws Exception {}}
- preHandle:目标方法之前执行,如果存在一个 HandlerInterceptor 的 preHandle 方法返回 false,则不执行目标方法
- postHandle:目标方法之后执行
- afterCompletion:不管方法执行成功还是失败,都会执行的方法
第一个HandlerInterceptor
创建拦截器 FirstInterceptor
public class FirstInterceptor implements HandlerInterceptor {@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {System.out.println("preHandle1");return HandlerInterceptor.super.preHandle(request, response, handler);}@Overridepublic void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {System.out.println("postHandle1");HandlerInterceptor.super.postHandle(request, response, handler, modelAndView);}@Overridepublic void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {System.out.println("afterCompletion1");HandlerInterceptor.super.afterCompletion(request, response, handler, ex);}
}
创建配置文件 InterceptorConfig
@Configuration
public class InterceptorConfig implements WebMvcConfigurer {@Overridepublic void addInterceptors(InterceptorRegistry registry) {registry.addInterceptor(new FirstInterceptor()).addPathPatterns("/interceptor/*");}
}
创建Controller InterceptorController
@RestController
@RequestMapping(value = "/interceptor")
public class InterceptorController {@GetMapping(value = "/simple")public void simple() {System.out.println("target");}
}
访问链接:http://localhost:8080/interceptor/simple
执行顺序
preHandle → targert → postHandle → afterCompletion
多个 HandlerInterceptor,方法的执行顺序
所有方法都正确执行
创建拦截器 SecondInterceptor、ThirdInterceptor
public class SecondInterceptor implements HandlerInterceptor {@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {System.out.println("preHandle2");return HandlerInterceptor.super.preHandle(request, response, handler);}@Overridepublic void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {System.out.println("postHandle2");HandlerInterceptor.super.postHandle(request, response, handler, modelAndView);}@Overridepublic void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {System.out.println("afterCompletion2");HandlerInterceptor.super.afterCompletion(request, response, handler, ex);}
}public class ThirdInterceptor implements HandlerInterceptor {@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {System.out.println("preHandle3");return HandlerInterceptor.super.preHandle(request, response, handler);}@Overridepublic void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {System.out.println("postHandle3");HandlerInterceptor.super.postHandle(request, response, handler, modelAndView);}@Overridepublic void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {System.out.println("afterCompletion3");HandlerInterceptor.super.afterCompletion(request, response, handler, ex);}
}
修改配置文件 InterceptorConfig
@Configuration
public class InterceptorConfig implements WebMvcConfigurer {@Overridepublic void addInterceptors(InterceptorRegistry registry) {registry.addInterceptor(new FirstInterceptor()).addPathPatterns("/interceptor/*");registry.addInterceptor(new SecondInterceptor()).addPathPatterns("/interceptor/*");registry.addInterceptor(new ThirdInterceptor()).addPathPatterns("/interceptor/*");}
}
访问链接:http://localhost:8080/interceptor/simple
图形化如下所示:
某个 preHandle 方法返回 false (或抛出异常)
将 SecondInterceptor 的 preHandle 方法的返回值改成 false
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {System.out.println("preHandle2");return false;
}
访问链接:http://localhost:8080/interceptor/simple
图形化如下所示:
某个 postHandle 方法返回抛出异常
SecondInterceptor 的 postHandle 方法抛出自定义异常
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {System.out.println("postHandle2");throw new RuntimeException("自定义异常");
}
访问链接:http://localhost:8080/interceptor/simple
图形化如下所示:
小结
- 正常执行
- preHandle 方法顺序执行
- postHandle 方法逆序执行
- 执行目标方法
- afterCompletion 方法逆序执行
- 某个 preHandle 方法返回 false (或抛出异常)
- 返回 false (或抛出异常)的拦截器及之前的拦截器的 preHandle 方法顺序执行
- 返回 false (或抛出异常)之前的拦截器的 afterCompletion 方法逆序执行
- 某个 postHandle 方法返回抛出异常
- preHandle 方法顺序执行
- 抛出异常之前的拦截器的 postHandle 方法逆序执行
- afterCompletion 方法逆序执行
源码解析
HandlerExecutionChain 添加 Interceptor
AbstractHandlerMapping#getHandlerExecutionChain
我们在上文中展示了三张图,其实它就是一个 HandlerExecutionChain 对象,其结构如下:
在目标方法之前,执行 Interceptor 的 preHandle 方法
DispatcherServlet#doDispatch
HandlerExecutionChain#applyPreHandle
只要一个拦截器的 preHandle 方法返回 fasle,则执行 triggerAfterCompletion 方法,并返回false,即不会执行目标方法
HandlerExecutionChain#triggerAfterCompletion
HandlerExecutionChain 通过属性 interceptorIndex 记录成功执行多少个拦截器的 preHandle 方法,然后逆序执行 afterCompletion 方法。我们需要注意的是,执行 afterCompletion 方法的时候都加了try...catch,即如果一个拦截器成功执行其 preHandle 方法,后续一定会执行其 afterCompletion 方法
在目标方法之后,执行 Interceptor 的 postHandle 方法
逆序执行 Interceptor 的 postHandle 方法。根据上文的分析,运行到这个阶段,所有拦截器的 preHandle 方法都正常执行了,即后续会执行所有拦截器的 afterCompletion 方法
执行 Interceptor 的 afterCompletion 方法
DispatcherServlet#processDispatchResult
不管方法是正常结束还是异常结束,如果一个拦截器成功执行其 preHandle 方法,后续一定会执行其 afterCompletion 方法