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

SpringMVC创建异步回调请求的4种方式

首先要明确一点,同步请求和异步请求对于客户端用户来讲是一样的,都是需客户端等待返回结果。不同之处在于请求到达服务器之后的处理方式,下面用两张图解释一下同步请求和异步请求在服务端处理方式的不同:

同步请求

异步请求

两个流程中客户端对Web容器的请求,都是同步的。因为它们在请求客户端时都处于阻塞等待状态,并没有进行异步处理。在Web容器部分,第一个流程采用同步请求,第二个流程采用异步回调的形式。通过异步处理,可以先释放容器分配给请求的线程与相关资源,减轻系统负担,从而增加了服务器对客户端请求的吞吐量。但并发请求量较大时,通常会通过负载均衡的方案来解决,而不是异步。

  1. 使用AsyncContext执行异步请求

package com.example.async;import java.io.IOException;
import javax.servlet.AsyncContext;
import javax.servlet.AsyncEvent;
import javax.servlet.AsyncListener;
import javax.servlet.http.HttpServletRequest;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;@RestController
public class AsyncContextController {@GetMapping("/asyncContext")@ResponseBodypublic String asyncTask(HttpServletRequest request) {AsyncContext asyncContext = request.startAsync();asyncContext.addListener(new AsyncListener() {@Overridepublic void onTimeout(AsyncEvent event) throws IOException {System.out.println("处理超时了...");}@Overridepublic void onStartAsync(AsyncEvent event) throws IOException {System.out.println("线程开始执行");}@Overridepublic void onError(AsyncEvent event) throws IOException {System.out.println("执行过程中发生错误:" + event.getThrowable().getMessage());}@Overridepublic void onComplete(AsyncEvent event) throws IOException {System.out.println("执行完成,释放资源");}});asyncContext.setTimeout(6000);asyncContext.start(new Runnable() {@Overridepublic void run() {try {Thread.sleep(5000);System.out.println("内部线程:" + Thread.currentThread().getName());asyncContext.getResponse().getWriter().println("async processing");} catch (Exception e) {System.out.println("异步处理发生异常:" + e.getMessage());}asyncContext.complete(); // 异步请求完成通知,整个请求完成}});System.out.println("主线程:" + Thread.currentThread().getName()); return "OK";}
}
  1. 使用Callable执行异步请求

package com.example.async;import java.util.concurrent.Callable;
import java.util.concurrent.TimeUnit;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;@RestController
public class CallableController {@GetMapping(path = "/callable")@ResponseBodypublic Callable<String> asyncRequest() {return () -> {TimeUnit.SECONDS.sleep(10);return "OK";};}
}
  1. 使用WebAsyncTask执行异步请求

package com.example.async;import java.util.concurrent.Callable;
import java.util.concurrent.TimeUnit;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.context.request.async.WebAsyncTask;@RestController
public class WebAsyncTaskController {@GetMapping("/webAsyncTask")@ResponseBodypublic WebAsyncTask<String> asyncTask() {WebAsyncTask<String> webAsyncTask = new WebAsyncTask<String>(1000l * 10, new Callable<String>() {@Overridepublic String call() throws Exception {TimeUnit.SECONDS.sleep(5);return "OK";}});webAsyncTask.onCompletion(new Runnable() {@Overridepublic void run() {System.out.println("调用完成");}});webAsyncTask.onTimeout(new Callable<String>() {@Overridepublic String call() throws Exception {return "Time Out";}});return webAsyncTask;}
}
  1. 使用DeferredResult执行异步请求

package com.example.async;import java.util.concurrent.TimeUnit;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.context.request.async.DeferredResult;@RestController
public class DeferredResultController {@GetMapping(path = "/deferredResult")@ResponseBodypublic DeferredResult<String> asyncRequest() {DeferredResult<String> deferredResult = new DeferredResult<>(1000L * 5, "失败");deferredResult.onTimeout(() -> {System.out.println("调用超时");deferredResult.setResult("调用超时");});deferredResult.onCompletion(() -> {System.out.println("调用完成");});new Thread(() -> {try {TimeUnit.SECONDS.sleep(10);deferredResult.setResult("OK");} catch (Exception e) {e.printStackTrace();}}).start();return deferredResult;}
}
  1. 另外:Spring Boot中使用注解@Async处理异步任务

@Async注解的异步操作和上文所诉的四种异步请求不同之处在于,使用@Async处理异步任务时没有异步回调响应客户端的流程:

使用@EnableAsync开启@Async

package com.example;import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.scheduling.annotation.EnableAsync;@EnableAsync
@SpringBootApplication
public class ExampleApplication {public static void main(String[] args) {SpringApplication.run(ExampleApplication.class, args);}}

如果将@Async加在Controller上或是 Controller 的方法上

package com.example.async;import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Async;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;@RestController
public class AsyncController {@Autowiredprivate TestService testService;@GetMapping("/async")@ResponseBody@Asyncpublic String asyncTask() {testService.doSomeThing();System.out.println("处理完成");return "OK";}
}

控制器立即会给客户端空响应,但是控制器方法依旧执行

如果将@Async加在Service上或是 Service 的方法上

package com.example.async;import java.util.concurrent.TimeUnit;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;@Service
public class TestService {@Asyncpublic void doSomeThing() {try {TimeUnit.SECONDS.sleep(5);} catch (InterruptedException e) {e.printStackTrace();}}
}

控制器不再等待Service方法执行完毕就响应客户端

相关文章:

SpringMVC创建异步回调请求的4种方式

首先要明确一点&#xff0c;同步请求和异步请求对于客户端用户来讲是一样的&#xff0c;都是需客户端等待返回结果。不同之处在于请求到达服务器之后的处理方式&#xff0c;下面用两张图解释一下同步请求和异步请求在服务端处理方式的不同&#xff1a;同步请求异步请求两个流程…...

MySQL(二)表的操作

一、创建表 CREATE TABLE table_name ( field1 datatype, field2 datatype, field3 datatype ) character set 字符集 collate 校验规则 engine 存储引擎; 说明&#xff1a; field 表示列名 datatype 表示列的类型 character set 字符集&#xff0c;如…...

SpringCloud - 入门

目录 服务架构演变 单体架构 分布式架构 分布式架构要考虑的问题 微服务 初步认识 案例Demo 服务拆分注意事项 服务拆分示例 服务调用 服务架构演变 单体架构 将业务的所有功能集中在一个项目中开发&#xff0c;打成一个包部署优点&#xff1a; 架构简单部署成本低缺…...

进一步了解C++函数的各种参数以及重载,了解C++部分的内存模型,C++独特的引用方式,巧妙替换指针,初步了解类与对象。满满的知识,希望大家能多多支持

C的编程精华&#xff0c;走过路过千万不要错过啊&#xff01;废话少说&#xff0c;我们直接进入正题&#xff01;&#xff01;&#xff01;&#xff01; 函数高级 C的函数提高 函数默认参数 在C中&#xff0c;函数的形参列表中的形参是可以有默认值的。 语法&#xff1a;返…...

Chapter6:机器人SLAM与自主导航

ROS1{\rm ROS1}ROS1的基础及应用&#xff0c;基于古月的课&#xff0c;各位可以去看&#xff0c;基于hawkbot{\rm hawkbot}hawkbot机器人进行实际操作。 ROS{\rm ROS}ROS版本&#xff1a;ROS1{\rm ROS1}ROS1的Melodic{\rm Melodic}Melodic&#xff1b;实际机器人&#xff1a;Ha…...

Sass的使用要点

Sass 是一个 CSS 预处理器&#xff0c;完全兼容所有版本的 CSS。实际上&#xff0c;Sass 并没有真正为 CSS 语言添加任何新功能。只是在许多情况下可以可以帮助我们减少 CSS 重复的代码&#xff0c;节省开发时间。 一、注释 方式一&#xff1a;双斜线 // 方式二&#xff1a;…...

计算机启动过程,从按下电源按钮到登录界面的详细步骤

1、背景 自接触计算机以来&#xff0c;一直困扰着我一个问题。当我们按下电脑的开机键后&#xff0c;具体发生了哪些过程呢&#xff1f;计算机启动的具体步骤是什么&#xff1f; 计算机启动过程通常分为五个步骤&#xff1a;电源自检、BIOS自检、引导设备选择、引导程序加载和…...

LeetCode 刷题之 BFS 广度优先搜索【Python实现】

1. BFS 算法框架 BFS&#xff1a;用来搜索 最短路径 比较合适&#xff0c;如&#xff1a;求二叉树最小深度、最少步数、最少交换次数&#xff0c;一般与 队列 搭配使用&#xff0c;空间复杂度比 DFS 大很多DFS&#xff1a;适合搜索全部的解&#xff0c;如&#xff1a;寻找最短…...

Hadoop01【尚硅谷】

大数据学习笔记 大数据概念 大数据&#xff1a;指无法在一定时间范围内用常规软件工具进行捕捉、管理和处理的数据集合&#xff0c;是需要新处理模式才能具有更强的决策力、洞察发现力和流程优化能力的海量、高增长率和多样化的信息资产。 主要解决&#xff0c;海量数据的存储…...

Echarts 配置横轴竖轴指示线,更换颜色、线型和大小

第018个点击查看专栏目录本示例是描述如何在Echarts上配置横轴竖轴指示线&#xff0c;更换颜色、线型和大小。方法很简单&#xff0c;参考示例源代码。 文章目录示例效果示例源代码&#xff08;共85行&#xff09;相关资料参考专栏介绍示例效果 示例源代码&#xff08;共85行&a…...

OpenAI 官方API Java版SDK,两行代码即可调用。包含GhatGPT问答接口。

声明&#xff1a;这是一个非官方的社区维护的库。 已经支持OpenAI官方的全部api&#xff0c;有bug欢迎朋友们指出&#xff0c;互相学习。 注意&#xff1a;由于这个接口&#xff1a; https://platform.openai.com/docs/api-reference/files/retrieve-content 免费用户无法使…...

SpringBoot 日志文件

(一)日志文件有什么用&#xff1f;除了发现和定位问题之外&#xff0c;我们还可以通过日志实现以下功能&#xff1a;记录用户登录日志&#xff0c;以便分析用户是正常登录还是恶意破解用户。记录系统的操作日志&#xff0c;以便数据恢复和定位操作 。记录程序的执行时间&#x…...

SQL71 检索供应商名称

描述Vendors表有字段供应商名称&#xff08;vend_name&#xff09;、供应商国家&#xff08;vend_country&#xff09;、供应商州&#xff08;vend_state&#xff09;vend_namevend_countryvend_stateappleUSACAvivoCNAshenzhenhuaweiCNAxian【问题】编写 SQL 语句&#xff0c;…...

02:入门篇 - 漫谈 CTK

作者: 一去、二三里 个人微信号: iwaleon 微信公众号: 高效程序员 十万个为什么 五千个在哪里?七千个怎么办?十万个为什么?。。。生活中,有很多奥秘在等着我们去思考、揭示! 同样地,在使用 CTK 时,很多小伙伴一定也存在诸多疑问: 为什么 CTK Plugin Framework 要借…...

SpringBoot常用注解

SpringBootApplication注解包含如下三个SpringBootConfigurationEnableAutoConfigurationComponentScanSpringBootConfiguration等同于Configuration&#xff0c;是属于spring的一个配置类这里的 Configuration 对我们来说并不陌生&#xff0c;它就是 JavaConfig 形式的 Spring…...

RBAC权限模型

什么是RBAC权限模型&#xff1f; RBAC是基于角色的访问控制&#xff0c;在RBAC中&#xff0c;权限与角色相关联&#xff0c;用户通过成为适当角色的成员而得到这些角色的权限。 1.0级 用户、角色、权限 2.0 权限分级 公司>部门>小组 2.1 权限继承 ps: 这个人是一个小组长…...

【郭东白架构课 模块一:生存法则】07|法则三:架构师如何找到自己的商业模式?

你好&#xff0c;我是郭东白&#xff0c;今天我们来聊聊架构活动中对商业价值的考量。 今天我们要讲的是架构师的第三个生存法则&#xff1a;作为一个架构师&#xff0c;必须要在有限的资源下最大化架构活动所带来的商业价值。对于任何一个架构活动而言&#xff0c;架构师的可…...

STM32 - 看门狗

独立看门狗 IWDG专业时钟LSI 低功耗仍可以运行对定时的控制比较松喂狗这些时间是按照40kHz时钟给出。实际上&#xff0c;MCU内部的RC频率会在30kHz到60kHz之间变化。此外&#xff0c;即使RC振荡器的频率是精确的&#xff0c;确切的时序仍然依赖于APB接口时钟与RC振荡器时钟之间…...

Redis集群搭建

一、哨兵模式 在 redis3.0之前&#xff0c;redis使用的哨兵架构&#xff0c;它借助 sentinel 工具来监控 master 节点的状态&#xff1b;如果 master 节点异常&#xff0c;则会做主从切换&#xff0c;将一台 slave 作为 master。 哨兵模式的缺点&#xff1a; &#xff08;1&…...

车载基础软件——AUTOSAR AP典型应用案例

我是穿拖鞋的汉子&#xff0c;魔都中一位坚持长期主义的工程师&#xff01; 最近不知道为何特别喜欢苏轼的一首词&#xff1a; 缺月挂疏桐&#xff0c;漏断人初静。谁见幽人独往来&#xff0c;缥缈孤鸿影。 惊起却回头&#xff0c;有恨无人省。拣尽寒枝不肯栖&#xff0c;寂寞…...

消息中间件----内存数据库 Redis7(第3章 Redis 命令)

Redis 根据命令所操作对象的不同&#xff0c;可以分为三大类&#xff1a;对 Redis 进行基础性操作的命令&#xff0c;对 Key 的操作命令&#xff0c;对 Value 的操作命令。3.1 Redis 基本命令首先通过 redis-cli 命令进入到 Redis 命令行客户端&#xff0c;然后再运行下面的命令…...

react-03-react-router-dom-路由

react-router-dom:react路由 印记中文:react-router-dom 1、路由原理 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><title>前端路由的基石_history</title> </head> <body><a hre…...

2自由度悬架LQR控制

目录 1 悬架系统 1.1 悬架结构示意图 1.2 悬架数学模型 1.3 路面激励 2.仿真分析 2.1simulink模型 2.2 仿真结果 2.3 结论 3. 总结 1 悬架系统 1.1 悬架结构示意图 1.2 悬架数学模型 其中&#xff1a;x1为悬架动扰度&#xff0c;x2为车身加速度&#xff0c;x3为轮胎…...

C语言返回类型为指针的一些经典题目(下)

续上一篇文章&#xff0c;上一篇文章题目都很经典&#xff0c;这一篇也不例外。一.返回类型为指针经典题目(下)1.代码(第六题)char *GetMemory3(int num) {char *p (char *)malloc(sizeof(char) * num);return p; } void Test3(void) {char *str NULL;str GetMemory3(100…...

OpenAI 官方api 阅读笔记

网站 API Key concepts Prompts and completions You input some text as a prompt, and the model will generate a text completion that attempts to match whatever context or pattern you gave it. Token  模型通过将文本分解成token来理解和处理, 处理token数量取…...

微服务项目【分布式锁】

创建Redisson模块 第1步&#xff1a;基于Spring Initialzr方式创建zmall-redisson模块 第2步&#xff1a;在zmall-redisson模块中添加相关依赖 <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</a…...

JavaWeb5-线程常用属性

目录 1.ID 2.名称 3.状态 4.优先级 5.是否守护线程 5.1.线程类型&#xff1a; ①用户线程&#xff08;main线程默认是用户线程&#xff09; ②守护线程&#xff08;后台/系统线程&#xff09; 5.2.守护线程作用 5.3.守护线程应用 5.4.守护线程使用 ①在用户线程&am…...

JVM调优及垃圾回收GC

一、说一说JVM的内存模型。JVM的运行时内存也叫做JVM堆&#xff0c;从GC的角度可以将JVM分为新生代、老年代和永久代。其中新生代默认占1/3堆内存空间&#xff0c;老年代默认占2/3堆内存空间&#xff0c;永久代占非常少的对内存空间。新生代又分为Eden区、SurvivorFrom区和Surv…...

JAVA练习53-打乱数组

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 目录 前言 一、题目-打乱数组 1.题目描述 2.思路与代码 2.1 思路 2.2 代码 总结 前言 提示&#xff1a;这里可以添加本文要记录的大概内容&#xff1a; 2月17日练习内…...

基于RK3588的嵌入式linux系统开发(三)——Uboot镜像文件合成

本章uboot镜像文件的合成包括官网必备文件rkbin下载和uboot镜像文件合成两部分内容&#xff0c;具体分别如下所述。 &#xff08;一&#xff09;下载rkbin文件包 以上uboot编译生成的uboot镜像不能直接烧录到板卡中运行&#xff0c;需要与atf、bl31、ddr配置文件等必备文件合成…...

哈尔滨百度推广排名/上海seo公司哪个靠谱

堆是一棵完全二叉树&#xff0c;对于最大堆来说&#xff0c;任何一个非叶子节点满足&#xff1a;结点的值大于其孩子结点的值。使用数组可以实现完全二叉树的结构。下标从1开始&#xff0c;一个结点i的左孩子下标为2*i&#xff0c;有孩子下标为2*i1。下面是实现一个简单的最大堆…...

wordpress支持系统/网站建设流程是什么

实网测试&#xff0c;可以理解为在用户实际网络环境资源进行测试的行为。为何需要实网测试呢&#xff1f; 单机的应用软件越来越少&#xff0c;当下的应用软件都需要涉及与服务器之间的交互&#xff0c;尤其是当前火热的云服务应用软件。 目前比较流行的网络视频播放软件&…...

wordpress 数字格式/网店seo关键词

一、params参数&#xff08;用的比较多&#xff09; 具体步骤&#xff1a; ①路由链接(携带参数)&#xff1a;<Link to/demo/test/tom/18}>详情</Link> ②注册路由(声明接收)&#xff1a;<Route path"/demo/test/:name/:age" component{Test}/> ③…...

店面设计属于什么设计/优化师的工作内容

表单验证 js验证 组件&#xff1a; easyui:http://www.jeasyui.net/ jQueryui&#xff1a;https://jqueryui.com/ bootstrap&#xff1a;http://www.bootcss.com/ 一、响应式&#xff1a; media 二、图标、字体 font-face 三、基本使用 !important   引用了其他样式之后&…...

企石做网站/昆山网站建设推广

台积电遭遇罕见的病毒攻击&#xff0c;虽然其声称各工厂已快速恢复生产&#xff0c;不过作为全球最大的芯片代工厂这必然会对其客户产生较大的影响&#xff0c;那么哪些芯片企业将会受到影响&#xff0c;对其客户又会造成怎么样的深远影响呢&#xff1f;台积电的工艺制程产能将…...

网站永久镜像怎么做/廊坊seo培训

最近DNN很受欢迎,博克圆有不少bloger对这个很有研究,并翻译了不少资料,ME也想看 看究竟,不过在看DNN之前,我决定先看看ASP.NET STARTER KIT的Portal Starter Kit,建立个简单的概念也许会对学习DNN有帮助了 我个人觉得Portal Starter Kit没有细看的必要,大概了解下面四点就可以…...