当前位置: 首页 > news >正文

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

执行顺序

preHandletargert → 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

图形化如下所示:

小结
  1. 正常执行
    1. preHandle 方法顺序执行
    2. postHandle 方法逆序执行
    3. 执行目标方法
    4. afterCompletion 方法逆序执行
  2. 某个 preHandle 方法返回 false (或抛出异常)
    1. 返回 false (或抛出异常)的拦截器及之前的拦截器的 preHandle 方法顺序执行
    2. 返回 false (或抛出异常)之前的拦截器的 afterCompletion 方法逆序执行
  3. 某个 postHandle 方法返回抛出异常
    1. preHandle 方法顺序执行
    2. 抛出异常之前的拦截器的 postHandle 方法逆序执行
    3. 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 方法

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • Rust代码答疑报错|Python一对一辅导答疑
  • sql查询报错空指针怎么解决?
  • Anything LLM ,构建自己的 RAG 架构 LLM,学习自己的知识库
  • HCIP之PPP协议(PAP认证,CHAP认证)、GRE、MGRE综合实验
  • git -.gitignore不生效的问题
  • React 18【实用教程】(2024最新版)
  • 从dev分支合并到master分支
  • Vue 3项目安装Element-Plus
  • el-table表格 及其el-pagination分页 封装及其使用
  • 【深度学习】sdxl的Lora训练技巧
  • day07:用户下单、订单支付
  • JUnit 单元测试
  • three完全开源扩展案例05-围栏着色器
  • 微信小程序 - 在视图组件上绑定函数并携带参数(事件对象自定义属性传参)
  • mysql-造数据/列转行
  • php的引用
  • 【个人向】《HTTP图解》阅后小结
  • C++回声服务器_9-epoll边缘触发模式版本服务器
  • Laravel Telescope:优雅的应用调试工具
  • nginx 配置多 域名 + 多 https
  • React 快速上手 - 06 容器组件、展示组件、操作组件
  • socket.io+express实现聊天室的思考(三)
  • 纯 javascript 半自动式下滑一定高度,导航栏固定
  • 记一次用 NodeJs 实现模拟登录的思路
  • 前嗅ForeSpider中数据浏览界面介绍
  • 线上 python http server profile 实践
  • 学习ES6 变量的解构赋值
  • 与 ConTeXt MkIV 官方文档的接驳
  • 不要一棍子打翻所有黑盒模型,其实可以让它们发挥作用 ...
  • 数据可视化之下发图实践
  • ​软考-高级-系统架构设计师教程(清华第2版)【第15章 面向服务架构设计理论与实践(P527~554)-思维导图】​
  • # Swust 12th acm 邀请赛# [ K ] 三角形判定 [题解]
  • ( 用例图)定义了系统的功能需求,它是从系统的外部看系统功能,并不描述系统内部对功能的具体实现
  • (13)DroneCAN 适配器节点(一)
  • (32位汇编 五)mov/add/sub/and/or/xor/not
  • (el-Date-Picker)操作(不使用 ts):Element-plus 中 DatePicker 组件的使用及输出想要日期格式需求的解决过程
  • (Python) SOAP Web Service (HTTP POST)
  • (TOJ2804)Even? Odd?
  • (二) 初入MySQL 【数据库管理】
  • (学习日记)2024.01.19
  • (转)JVM内存分配 -Xms128m -Xmx512m -XX:PermSize=128m -XX:MaxPermSize=512m
  • (转)一些感悟
  • *算法训练(leetcode)第四十七天 | 并查集理论基础、107. 寻找存在的路径
  • .bat批处理(九):替换带有等号=的字符串的子串
  • .cn根服务器被攻击之后
  • .dat文件写入byte类型数组_用Python从Abaqus导出txt、dat数据
  • .FileZilla的使用和主动模式被动模式介绍
  • .net mvc部分视图
  • .net 后台导出excel ,word
  • .net打印*三角形
  • /etc/fstab和/etc/mtab的区别
  • @RequestParam详解
  • [C/C++入门][ifelse]20、闰年判断
  • [C++数据结构](22)哈希表与unordered_set,unordered_map实现
  • [CodeForces-759D]Bacterial Melee