Spring:spring-web中DeferredResult执行过程分析

news2024/11/26 14:43:12

       对于HTTP请求的处理,有时处理请求的时间较长,可能会采用异步处理方式来处理。一般常用的异步处理方式是采用DeferredResult,本文会简单分析一下spring-web的整个处理过程。

     首先,提供一个简单的DeferredResult例子:

@RestController
public class TestController {

	@PostMapping("/test/doRequest")
	public DeferredResult<String> doRequest(@RequestBody(required = false) String body, HttpServletRequest request) {
		System.out.println("======================" + request.getDispatcherType());
		String ret = "ok:" + System.currentTimeMillis();

		DeferredResult<String> dr = new DeferredResult<String>(10000L);
		Executors.newSingleThreadExecutor().execute(new Runnable() {

			public void run() {
				try {
					Thread.sleep(5000);
				} catch (InterruptedException e) {}
				dr.setResult(ret);
			}
		});

		return dr;
	}
}

DeferredResult的内部实际上是使用servlet3.0规范中异步servlet实现的。

以下对版本spring-web-5.2.10.Release的代码进行分析。

HTTP主要是由org.springframework.web.servlet.DispatcherServlet的doDispatch(...)处理的,其中的主要处理方法如下:

 (1)、(4)会分别调用org.springframework.web.servlet.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 {
	}
}

(6)会调用org.springframework.web.servlet.AsyncHandlerInterceptor中的对应方法:

public interface AsyncHandlerInterceptor extends HandlerInterceptor {

	default void afterConcurrentHandlingStarted(HttpServletRequest request, HttpServletResponse response,
			Object handler) throws Exception {
	}
}

从(2)进入后,会调用到org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod的如下方法:

(7)会调用到TestController.doRequest方法,返回的returnValue就是DeferredResult对象。

(8)中会调用org.springframework.web.servlet.mvc.method.annotation.DeferredResultMethodReturnValueHandler的如下方法:

 其中最后一行调用的是org.springframework.web.context.request.async.WebAsyncManager如下方法:

(9)会调用如下方法

其中483行会实际调用javax.servlet.ServletRequest.startAsync(ServletRequest servletRequest,ServletResponse servletResponse)的一个实现,从而开启一个异步处理流程。

(10)调用的是org.springframework.web.context.request.async.DeferredResult如下方法:

 这里需要特别关注(11),它分2种情况:
#1.如果DeferredResult.setResult(...)在此之前未被调用过,则直接返回
#2.如果DeferredResult.setResult(...)在此之前已被调用过,则执行(12)

其中(12)会调用(13),(13)会调用(14),(14)实际会调用javax.servlet.ServletRequest.dispatch()的实现。若此方法被调用,实际会在servlet容器内部再发起一个针对/test/doRequest的请求。

然后返回到(2)后继续向下执行到(3),(3)最终调用的是org.springframework.web.context.request.async.StandardServletAsyncWebRequest如下方法:

本质上是调用javax.servlet.ServletRequest.isAsyncStarted()的实现。

 此时(3)的值为false,程序直接返回。

这里有一个可疑的地方,如果TestController的代码为:

@RestController
public class TestController {

	@PostMapping("/test/doRequest")
	public DeferredResult<String> doRequest(@RequestBody(required = false) String body, HttpServletRequest request) {
		System.out.println("======================" + request.getDispatcherType());
		String ret = "ok:" + System.currentTimeMillis();

		DeferredResult<String> dr = new DeferredResult<String>(10000L);
		dr.setResult(ret);

		return dr;
	}
}

即测试代码中如上直接给DeferredResult设置值,执行javax.servlet.ServletRequest.dispatch()后,根据servlet3.0规范,此时javax.servlet.ServletRequest.isAsyncStarted()应该返回false。但实际用tomcat、jetty都试过,都是返回true,整个流程执行的没有问题。可放到webloigc中执行时,则是返回false,执行整个流程的会报错。

无论是#1还是#2,最终都会调用到(13),从而在servlet容器内部再发起一个针对/test/doRequest的请求,此时程序会再次执行到(2),然后会在org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter的(15)中获取到DeferredResult中设置的值

最终由org.springframework.web.servlet.mvc.method.annotation.RequestResponseBodyMethodProcesso的handleReturnValue方法将返回写回给客户端。

 参考文档

The Java EE Tutorial:17.12 Asynchronous Processing
spring-framework-docs:1.6. Asynchronous Requests

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/585753.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

C++map和set

目录&#xff1a; 什么是关联式容器&#xff1f;键值对树形结构的关联式容器 set的概念multiset的使用pair和make_pair map的概念用“[]”实现统计水果的次数 multimap的使用 什么是关联式容器&#xff1f; 在初阶阶段&#xff0c;我们已经接触过STL中的部分容器&#xff0c;比…

Centos7 Failed to start login service 问题

最近发现Centos7有个问题&#xff0c;用普通用户登录的时候&#xff0c;打开命令窗口无法进行操作一直卡在那里&#xff0c;但切换到root用户后命令输入又正常。因为我需要从 window 上的 SecureCRT 去连接 Centos7&#xff0c;每次都需要用户登录&#xff0c;然后把防火墙关闭…

TLD7002学习笔记(一)-芯片介绍

文章目录 1. 前言2. TLD7002-16ES简介3. TLD7002-16ES基本功能介绍3.1 引脚和功能框图3.2 状态机3.2.1 正常工作时状态机3.2.2 OTP烧录或者仿真时的状态机 3.3 GPIN0和GPIN1引脚3.4 器件地址3.5 电流配置3.6 PWM配置3.7 并行输出&热降额&热过载保护 TLD7002-16ES诊断功…

高完整性系统:INTRODUCING ADA

目录 1. ADA的历史 2. ADA的特点 2.1 Strong, Static Typing 强语言、强静态类型语言 2.1.1 ADA is Strong, Static Typing 2.1.2 C is Weak, Static Typing 2.2 Module System 2.3 Portable 2.3.1 ADA 2.3.2 C 2.3.3 Cost of Runtime Checking 2.4 Readability …

Java jvm调优

系列文章目录 文章目录 系列文章目录前言JVM 基础面试题11. JDK&#xff0c;JRE以及JVM的关系2. 我们的编译器到底干了什么事&#xff1f;3. 类加载机制是什么&#xff1f;3.1 装载(Load)3.2 链接(Link)验证(Verify)准备(Prepare)解析(Resolve) 3.3 初始化(Initialize) 4. 类加…

chatgpt赋能python:Python三次幂与其应用

Python三次幂与其应用 Python是一种高级编程语言&#xff0c;因其简单易用的语法和广泛应用而备受欢迎。在该语言中&#xff0c;三次幂是其中一个常用操作之一。本文将介绍Python三次幂的概念及其应用&#xff0c;为您带来有价值的参考。 什么是Python三次幂&#xff1f; Py…

KubeSphere 社区双周报 | 杭州 Meetup 报名中 | 2023.05.12-05.25

KubeSphere 社区双周报主要整理展示新增的贡献者名单和证书、新增的讲师证书以及两周内提交过 commit 的贡献者&#xff0c;并对近期重要的 PR 进行解析&#xff0c;同时还包含了线上/线下活动和布道推广等一系列社区动态。 本次双周报涵盖时间为&#xff1a;2023.05.12-2023.…

Linux - Java 8 入门安装与重装教程集锦

一、入门初始安装 1. 具体安装教程 1. linux 系统中如何安装java环境&#xff08;通过tar.gz文件&#xff09; 安装包下载链接 Java 的 tar.gz 安装包下载链接传送门 Linux 系统的 Java 环境变量配置教程 1. linux查看java版本&#xff0c;以及配置java home 2. Linux环…

stackqueue

这篇主要讲栈(stack)和队列(queue)&#xff0c;实际要学习的数据结构有三个&#xff1a;stack、queue、priority_queue 这些数据结构已经不属于容器了&#xff0c;而是容器适配器。 list的第二个参数是空间配置器&#xff0c;支持申请空间&#xff1b;而list和queue的第二个参…

Windows下利用Anaconda创建多个CUDA环境

参考 https://blog.csdn.net/qq_42395917/article/details/126237388 https://blog.csdn.net/qq_42406643/article/details/109545766 (待学习补充) https://blog.csdn.net/qq_43919533/article/details/125694437 (待学习补充) 安装cudatoolkit和cudnn # 前提是我已经安装了…

【Python 打包应用发布程序】零基础也能轻松掌握的学习路线与参考资料

Python是一种流行的编程语言&#xff0c;因其易学易用、灵活和高效而受到广泛关注和应用&#xff0c;尤其是在开发Web应用、数据科学和人工智能方面。Python的强大之处在于其丰富的第三方库和工具&#xff0c;可以让开发者轻松地构建复杂的应用程序和脚本工具。但是&#xff0c…

完全掌握git入门到精通各类免费书籍整理

大型软件项目开发&#xff0c;多人群组开发都离不开的版本控制工具 git&#xff0c;命令简单&#xff0c;想要完全掌握却需要付出一点时间。我们将一些评价较高的git免费学习资料网站做了整理&#xff0c;收录到 学习使用git完全指南各种免费书籍分享 完全掌握git入门到精通各…

【IDEA插件开发】快速入门系列01 开发一个简单的Idea插件

IDEA插件开发流程 IDEA插件开发官方文档 英文好的建议阅读官方文档 IDEA插件开发官方文档&#xff1a;https://plugins.jetbrains.com/docs/intellij/welcome.html 搭建IDEA插件开发环境 1.安装社区版IDEA 在这里我们需要下载IDEA社区版的历史版本。 历史版本的下载网址&a…

自学黑客?一般人我劝你还是算了吧

博主本人 18年就读于一所普通的本科学校&#xff0c;21年 6 月在三年经验的时候顺利通过校招实习面试进入大厂&#xff0c;现就职于某大厂安全联合实验室。 我为啥说自学黑客&网络安全&#xff0c;一般人我还是劝你算了吧。因为我就是那个不一般的人。 首先我谈下对黑客&am…

Java日期时间调整的几种方式

一、Calendar类 我们现在已经能够格式化并创建一个日期对象了&#xff0c;但是我们如何才能设置和获取日期数据的特定部分呢&#xff0c;比如说小时&#xff0c;日&#xff0c;或者分钟? 我们又如何在日期的这些部分加上或者减去值呢? 答案是使用Calendar 类。 Calendar类的…

六、基本数据类型

数据类型 一、基本数据类型 以下是go中可用的基本数据类型 1.1 布尔型bool 布尔型的值只可以是常量 true 或者 false。一个简单的例子&#xff1a;var b bool true 1.2 数值型 1、整数型 int8 有符号 8 位整型 (-128 到 127) 长度&#xff1a;8bit int16 有符号 16 位整…

jmeter接口工具使用详解之基础介绍

目录 一、优点 二、安装及下载 三、基础构成 jmeter是一款优秀的开源性能测试工具&#xff0c; 一、优点 1、开源工具&#xff0c;可扩展性非常好 2、高可扩展性&#xff0c;用户可自定义调试相关模块代码 3、精心简单的GUI设计&#xff0c;小巧灵活 4、完全的可移植性…

电子科技大学编译原理复习笔记(五):词法分析

目录 前言 重点一览 词法分析概述 词法分析的功能 词法分析器的输出形式 词法分析器的结构 状态转换图 状态转换图的构造 词法分析器的设计 基本结构 内容 符号表 目的 组成 在词法分析中的作用 符号表的一般形式 常用的符号表结构 总结与补充 为何分离词法…

小学百分数思维导图怎么画?这样制作不出错

百分数是数学中的一个重要概念&#xff0c;它用于表示一个数在另一个数中所占的比例。在日常生活中&#xff0c;我们经常使用百分数进行计算和比较。而百分数思维导图是一种图形化的表示方法&#xff0c;用于展示数值之间的比例关系。它通过将数值转化为百分数的形式&#xff0…

python学习——描述统计df.describe

文章目录 1 描述统计1.1 查看常见统计量 describe1.2 一般对数值型数据统计1.2.1 基于非空数值统计sum\mean\max\min\var\std1.2.2 每一列中最大值的行索引 idxmax1.2.3 每一行中最大值的列索引 idxmax&#xff08;axis 1&#xff09;1.2.4 非空的数量 count() 1.3 一般对字符…