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会执行两次相关推荐

  1. Spring MVC开发步骤以及执行流程

    Spring MVC开发步骤以及执行流程 开发步骤 1.在web.xml中定义前端控制器DispatcherServlet来拦截用户请求. 2.如果要以post方式提交请求,则定义包含表单数据的jsp ...

  2. Spring MVC拦截器的执行流程

    本节我们主要讲解 SpringMVC 拦截器的执行流程.分两部分介绍,首先介绍单个拦截器执行流程然后介绍多个拦截器的执行流程. 单个拦截器的执行流程 在配置文件中如果只定义了一个拦截器,程序将首先执行 ...

  3. Spring mvc 启动配置文件加载两遍问题

    问题描述 在使用spring mvc 启动的时候,用到了一个在程序启动时加载的配置方法init-method="initLoad",并启动多线程来做数据同步,但是在程序启动之后发现 ...

  4. Spring MVC 实践 - Base

    Spring MVC 实践 标签 : Java与Web Spring Web MVC Spring-Web-MVC是一种基于请求驱动的轻量级Web-MVC设计模式框架, Spring MVC使用MVC ...

  5. Spring MVC拦截器~~~登陆验证拦截

    [ 30 分 钟 轻 松 入 门 Spring MVC][web 三 大 组 件 之 ~ ~ Filter 过 滤 器] Interceptor 拦截器学习: 1.了解spring mvc拦截器的概念 ...

  6. 编写 Spring MVC 控制器的 14 个技巧

    欢迎关注方志朋的博客,回复"666"获面试宝典 通常,在Spring MVC中,我们编写一个控制器类来处理来自客户端的请求.然后,控制器调用业务类来处理与业务相关的任务,然后将客户 ...

  7. 14 个 Spring MVC 顶级技巧,随时用随时爽,一直用一直爽

    点击上方蓝色"方志朋",选择"设为星标" 回复"666"获取独家整理的学习资料! 译文:blog.csdn.net/Summer_Lyf/a ...

  8. 分享 14 个 Spring MVC 顶级技巧!

    点击上方"方志朋",选择"设为星标" 回复"666"获取新整理的面试文章 通常,在Spring MVC中,我们编写一个控制器类来处理来自客户 ...

  9. requestmapping默认是get还是post_编写Spring MVC控制器的14个技巧,你今天get到了吗?...

    Java面试笔试面经.Java技术每天学习一点 公众号Java面试 关注我不迷路 原文:http://dzone.com/articles/14-tips-for-writing-spring-mvc ...

最新文章

  1. 如何在arXiv上发表一篇文章
  2. 统计学习方法|朴素贝叶斯原理剖析及实现
  3. Matlab中存储及读取数据
  4. mysql cluster java_Java学习笔记(十):MySQL集群安装配置
  5. Python基础day02【if结构、if elif 结构、while循环、for循环、Break和continue、Debug 调试、三目运算、循环 else 结构】
  6. 什么时候用#{},什么时候用${}?
  7. java javax.xml.ws_如何通过javax.xml.ws.Service进行调用
  8. 关于JS闭包,作者不详(转)
  9. 拼接 结果集_JUST技术:利用轨迹拼接分析实时可达区域|技术前沿
  10. console_init初始化的研究
  11. Python函数相关笔记
  12. Hue使用之Inceptor篇
  13. 锐捷长ping_锐捷 ping 网关通 ping 机器不通
  14. Java并发包源码学习系列:AQS共享式与独占式获取与释放资源的区别
  15. 【.Net码农】ListT 类
  16. mfc将图形涂满颜色,(c++)使用顺序栈
  17. C#datagridview中双缓存Dgv
  18. matlab在sin处出现解析错误,破除“解析包时出现错误”方法大全,全部都在这了!...
  19. EOS智能合约开发系列(11): 多重签名
  20. 【知乎高赞】软件测试工程师应该怎样规划自己?成为年薪30W+测试工程师(乾坤未定,皆是黑马)

热门文章

  1. Ninite一次安装所有您喜欢的Windows程序
  2. Design A Pastebin
  3. Android 布局管理器
  4. SpringBoot集成Redis解决乱码问题 - \xAC\xED\x00\x05t\x00
  5. 【优化求解】基于新授粉方式的花授粉算法(NMFPA)求解单标目优化问题附matlab代码
  6. 全球及中国β-胡萝卜素行业发展展望及投资战略研究报告2022-2028年
  7. 华为一出鸿蒙开 鲲鹏展翅九万里,科技 _ 不止“鸿蒙”,还有子龙、浩天、青鸟、朱雀……华为简直注册了整本《山海经》!中国人有多浪漫,看这些名字就知道了...
  8. Unity3D学习笔记(四)牧师和魔鬼游戏改进
  9. struts2控制器及拦截器返回JSON格式数据
  10. 蓝牙解锁Mac工具 - BLEUnlock