为什么有时候spring mvc的interceptor会执行两次
spring mvc的拦截器大家应该都不陌生,可以在进入响应controller之前以及之后进行一些处理。
但有些情况下,拦截器中的preHandle方法总会执行两次,这是为何?
在解答此问题之前,我们先创建一个简单的controller
@RestController
public class HelloWorld {@GetMapping("/hello")public String hello() {System.out.println("== Hello ==");return "hello";}
}
为了更加清楚的描述问题,这里创建两个拦截器
@Configuration
public class WebConfig extends DelegatingWebMvcConfiguration {@Overrideprotected void addInterceptors(InterceptorRegistry registry) {registry.addInterceptor(new HandlerInterceptorAdapter() {@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {System.out.println("====> Pre Handle A " + Thread.currentThread().getId());return true;}@Overridepublic void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable Exception ex) throws Exception {System.out.println("After Completion A <==== " + Thread.currentThread().getId());}@Overridepublic void afterConcurrentHandlingStarted(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {System.out.println("After Concurrent Started A <==== " + Thread.currentThread().getId());}@Overridepublic void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable ModelAndView modelAndView) throws Exception {System.out.println("Post Handle A <==== " + Thread.currentThread().getId());}}).addPathPatterns("/**").order(1);registry.addInterceptor(new HandlerInterceptorAdapter() {@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {System.out.println("====> Pre Handle B " + Thread.currentThread().getId());return true;}@Overridepublic void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable Exception ex) throws Exception {System.out.println("After Completion B <==== " + Thread.currentThread().getId());}@Overridepublic void afterConcurrentHandlingStarted(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {System.out.println("After Concurrent Started B <==== " + Thread.currentThread().getId());}@Overridepublic void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable ModelAndView modelAndView) throws Exception {System.out.println("Post Handle B <==== " + Thread.currentThread().getId());}}).addPathPatterns("/**").order(2);super.addInterceptors(registry);}
}
在拦截器实现中,我们特意打印了当前线程的线程号。
访问 /hello
,我们可以得到如下输出
====> Pre Handle A 68
====> Pre Handle B 68
== Hello ==
Post Handle B <==== 68
Post Handle A <==== 68
After Completion B <==== 68
After Completion A <==== 68
可以看到,spring interceptor的运行机制就像剥洋葱一样,且对于同一个请求整个运行过程在同一个线程内完成。
接下来定义另一个controller,并返回StreamingResponseBody
@RestController
public class HelloWorld {@GetMapping("/streaming")public StreamingResponseBody streaming() {System.out.println("== Streaming ==");return (OutputStream outputStream) -> {outputStream.write("streaming".getBytes());outputStream.flush();outputStream.close();};}@GetMapping("/hello")public String hello() {System.out.println("== Hello ==");return "hello";}
}
此时访问 /streaming
,可以得到如下输出
====> Pre Handle A 74
====> Pre Handle B 74
== Streaming ==
After Concurrent Started B <==== 74
After Concurrent Started A <==== 74
====> Pre Handle A 75
====> Pre Handle B 75
Post Handle B <==== 75
Post Handle A <==== 75
After Completion B <==== 75
After Completion A <==== 75
从输出中可以看出,整个请求过程使用了两个线程,并且调用了拦截器中的afterConcurrentHandlingStarted方法。到这里各位看官应该就明白了,对于concurrent类型的返回值,spring会启用一个新的线程来处理concurrent类型消息,在新的线程中会重新调用preHandle方法。
那,postHandle方法是哪个线程在调用呢?各位如果感兴趣的话可以深入研究一下!
为什么有时候spring mvc的interceptor会执行两次相关推荐
- Spring MVC开发步骤以及执行流程
Spring MVC开发步骤以及执行流程 开发步骤 1.在web.xml中定义前端控制器DispatcherServlet来拦截用户请求. 2.如果要以post方式提交请求,则定义包含表单数据的jsp ...
- Spring MVC拦截器的执行流程
本节我们主要讲解 SpringMVC 拦截器的执行流程.分两部分介绍,首先介绍单个拦截器执行流程然后介绍多个拦截器的执行流程. 单个拦截器的执行流程 在配置文件中如果只定义了一个拦截器,程序将首先执行 ...
- Spring mvc 启动配置文件加载两遍问题
问题描述 在使用spring mvc 启动的时候,用到了一个在程序启动时加载的配置方法init-method="initLoad",并启动多线程来做数据同步,但是在程序启动之后发现 ...
- Spring MVC 实践 - Base
Spring MVC 实践 标签 : Java与Web Spring Web MVC Spring-Web-MVC是一种基于请求驱动的轻量级Web-MVC设计模式框架, Spring MVC使用MVC ...
- Spring MVC拦截器~~~登陆验证拦截
[ 30 分 钟 轻 松 入 门 Spring MVC][web 三 大 组 件 之 ~ ~ Filter 过 滤 器] Interceptor 拦截器学习: 1.了解spring mvc拦截器的概念 ...
- 编写 Spring MVC 控制器的 14 个技巧
欢迎关注方志朋的博客,回复"666"获面试宝典 通常,在Spring MVC中,我们编写一个控制器类来处理来自客户端的请求.然后,控制器调用业务类来处理与业务相关的任务,然后将客户 ...
- 14 个 Spring MVC 顶级技巧,随时用随时爽,一直用一直爽
点击上方蓝色"方志朋",选择"设为星标" 回复"666"获取独家整理的学习资料! 译文:blog.csdn.net/Summer_Lyf/a ...
- 分享 14 个 Spring MVC 顶级技巧!
点击上方"方志朋",选择"设为星标" 回复"666"获取新整理的面试文章 通常,在Spring MVC中,我们编写一个控制器类来处理来自客户 ...
- requestmapping默认是get还是post_编写Spring MVC控制器的14个技巧,你今天get到了吗?...
Java面试笔试面经.Java技术每天学习一点 公众号Java面试 关注我不迷路 原文:http://dzone.com/articles/14-tips-for-writing-spring-mvc ...
最新文章
- 如何在arXiv上发表一篇文章
- 统计学习方法|朴素贝叶斯原理剖析及实现
- Matlab中存储及读取数据
- mysql cluster java_Java学习笔记(十):MySQL集群安装配置
- Python基础day02【if结构、if elif 结构、while循环、for循环、Break和continue、Debug 调试、三目运算、循环 else 结构】
- 什么时候用#{},什么时候用${}?
- java javax.xml.ws_如何通过javax.xml.ws.Service进行调用
- 关于JS闭包,作者不详(转)
- 拼接 结果集_JUST技术:利用轨迹拼接分析实时可达区域|技术前沿
- console_init初始化的研究
- Python函数相关笔记
- Hue使用之Inceptor篇
- 锐捷长ping_锐捷 ping 网关通 ping 机器不通
- Java并发包源码学习系列:AQS共享式与独占式获取与释放资源的区别
- 【.Net码农】ListT 类
- mfc将图形涂满颜色,(c++)使用顺序栈
- C#datagridview中双缓存Dgv
- matlab在sin处出现解析错误,破除“解析包时出现错误”方法大全,全部都在这了!...
- EOS智能合约开发系列(11): 多重签名
- 【知乎高赞】软件测试工程师应该怎样规划自己?成为年薪30W+测试工程师(乾坤未定,皆是黑马)
热门文章
- Ninite一次安装所有您喜欢的Windows程序
- Design A Pastebin
- Android 布局管理器
- SpringBoot集成Redis解决乱码问题 - \xAC\xED\x00\x05t\x00
- 【优化求解】基于新授粉方式的花授粉算法(NMFPA)求解单标目优化问题附matlab代码
- 全球及中国β-胡萝卜素行业发展展望及投资战略研究报告2022-2028年
- 华为一出鸿蒙开 鲲鹏展翅九万里,科技 _ 不止“鸿蒙”,还有子龙、浩天、青鸟、朱雀……华为简直注册了整本《山海经》!中国人有多浪漫,看这些名字就知道了...
- Unity3D学习笔记(四)牧师和魔鬼游戏改进
- struts2控制器及拦截器返回JSON格式数据
- 蓝牙解锁Mac工具 - BLEUnlock