使用DeferredResult来设计异步接口

文章目录

    • DeferredResult 介绍
    • 思路
    • Demo搭建
      • 1.定义一个抽象的请求体
      • 2.定义一个接口返回体
      • 3.定义一个接口请求体继承抽象类AsynTaskBaseRequest<T<T>>
      • 4.定义seveice类,并声明一个异步方法(Async注解)
      • 5.定义一个返回DeferredResult的接口
    • 结果验证

DeferredResult 介绍

DeferredResult 是 Spring 框架中的一种异步处理方式,它可以在处理请求时,将请求的结果暂时挂起,等待后续的处理结果再返回给客户端。这种方式可以有效地提高系统的并发处理能力,减少系统的响应时间,提高用户体验。

DeferredResult 的原理是基于 Servlet 3.0规范中的异步处理机制实现的。在 Servlet 3.0中,可以通过AsyncContext 来实现异步处理。当一个请求进入 Servlet 容器时,容器会创建一个 AsyncContext 对象,并将请求的处理交给该对象。在处理请求的过程中,如果需要进行异步处理,可以通过 AsyncContext 对象来实现。

DeferredResult是Spring框架中的一个类,用于实现异步处理和响应。它允许在处理请求时,将结果封装为一个DeferredResult对象,然后将该对象返回给客户端。这样客户端就可以继续执行其他操作,而不需要等待结果返回。 在处理请求的过程中,可以通过调用DeferredResult对象的方法setResult设置结果值。这个过程可以在任何时间点发生,甚至可以在另一个线程中。一旦结果被设置,客户端将收到响应。

tomcat 的线程池大小是有限的,在高并发场景下,如果我们的一些业务逻辑处理慢的话,会渐渐地占满 tomcat 线程,这样就无法处理新的请求,所以一些处理缓慢的业务我们会放到业务线程池中处理,但单纯的放到业务线程池中处理的话,我们无法得知其什么时候处理完,也无法将处理完的结果和之前的请求匹配上,所以常做的方式就是轮询。而 DeferredResult 的做法就类似仅把事情安排好,不会管事情做好没,tomcat 线程就释放走了,注意此时不会给请求方(如浏览器)任何响应,而是将请求存放在一边,咱先不管它,等后面有结果了再把之前的请求拿来,把值响应给请求方。

思路

我们可以借助DeferredResult 的异步处理方式,提前将请求的结果应答给客户端,再执行耗时较长或无事务要求业务代码,类似于开了一个新的线程。当然这种只适用于客户端与服务端无强制事务关联的场景。

Demo搭建

1.定义一个抽象的请求体

import org.springframework.http.ResponseEntity;
import org.springframework.web.context.request.async.DeferredResult;

public abstract class AsynTaskBaseRequest<T> {

    protected DeferredResult<ResponseEntity<T>> result;

    public abstract void makeErrorResponseMsg(int code, String message);

    public abstract void makeSuccessResponseMsg();

    protected AsynTaskBaseRequest() {
        this.result = new DeferredResult<>();
    }

    public DeferredResult<ResponseEntity<T>> getResult() {
        return result;
    }

    public void setResult(DeferredResult<ResponseEntity<T>> result) {
        this.result = result;
    }
}

2.定义一个接口返回体

import com.fasterxml.jackson.annotation.JsonProperty;

public class AsynTaskBaseResponse {
    @JsonProperty(value = "code")
    private int code;
    @JsonProperty(value = "messages")
    private String messages;

    public AsynTaskBaseResponse() {
    }

    public AsynTaskBaseResponse(int code, String messages) {
        this.code = code;
        this.messages = messages;
    }

    public int getCode() {
        return code;
    }

    public void setCode(int code) {
        this.code = code;
    }

    public String getMessages() {
        return messages;
    }

    public void setMessages(String messages) {
        this.messages = messages;
    }
}

3.定义一个接口请求体继承抽象类AsynTaskBaseRequest<T>

import com.wjw.service.common.AsynTaskBaseRequest;
import com.wjw.service.common.AsynTaskBaseResponse;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;

public class DeferredResultRequestBody extends AsynTaskBaseRequest<AsynTaskBaseResponse> {

    public DeferredResultRequestBody() {
        super();
    }

    @Override
    public void makeErrorResponseMsg(int code, String message) {
        AsynTaskBaseResponse response = new AsynTaskBaseResponse(code, message);
        ResponseEntity<AsynTaskBaseResponse> responseEntity = new ResponseEntity<>(response, HttpStatus.BAD_REQUEST);
        result.setResult(responseEntity);
    }

    @Override
    public void makeSuccessResponseMsg() {
        AsynTaskBaseResponse response = new AsynTaskBaseResponse(0, "success");
        ResponseEntity<AsynTaskBaseResponse> responseEntity = new ResponseEntity<>(response, HttpStatus.OK);
        result.setResult(responseEntity);
    }
}

4.定义seveice类,并声明一个异步方法(Async注解)

使用@Async异步注解时首先要确认你的springboot项目是否开启了异步功能,检查启动类中是否加了@EnableAsync注解

在这里插入图片描述
Async 在未指定线程池时,使用的是springBoot内置的线程池,那如何指定使用自定义的线程池呢?可参考我的另一篇笔记。https://blog.csdn.net/weixin_44054222/article/details/107018400

import com.wjw.service.RequestParamer.DeferredResultRequestBody;
import org.springframework.http.HttpStatus;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;

@Service("DeferredResultService")
public class DeferredResultService {

    @Async
    public void demoTest(DeferredResultRequestBody requestBody){
         try {
            System.out.println("-----------接口应答前-------------");
            Thread.sleep(3 * 1000);
            requestBody.makeSuccessResponseMsg();
            System.out.println("-----------接口应答后-------------");
            Thread.sleep(10 * 1000);
            System.out.println("-----------执行完毕-------------");
        } catch (Exception e) {
            requestBody.makeErrorResponseMsg(HttpStatus.BAD_REQUEST.value(), e.getMessage());
        }
    }
}

5.定义一个返回DeferredResult的接口

import com.wjw.service.RequestParamer.DeferredResultRequestBody;
import com.wjw.service.common.AsynTaskBaseResponse;
import com.wjw.service.service.DeferredResultService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.context.request.async.DeferredResult;

@RestController
@RequestMapping("/services/demo/v1")
public class DeferredResultController {

    @Autowired
    private DeferredResultService deferredResultService;

    @GetMapping("/demo/test")
    public DeferredResult<ResponseEntity<AsynTaskBaseResponse>> test() {
        DeferredResultRequestBody requestBody = new DeferredResultRequestBody();
        deferredResultService.demoTest(requestBody);
        return requestBody.getResult();
    }
}

结果验证

这时如果调用接口控制台首先会打印"接口应答前",紧接着3s后收到接口的200 ok应答并打印”接口应答后“,等待10s打印”执行完毕“。

在这里插入图片描述

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

一篇文章带你搞懂Java多态的概念、优点、实现多态的方式、以及不同方式的区别

一篇文章带你搞懂Java多态的概念、优点、使用场景 基本概念 ​ **多态&#xff08;Polymorphism&#xff09;是面向对象编程的一个重要特性&#xff0c;它指的是同一个行为具有多个不同表现形式或形态的能力。**它允许我们使用父类的引用变量来引用子类的对象&#xff0c;并根…

SpringBoot第29讲:SpringBoot集成MySQL - MyBatis-Plus代码自动生成

SpringBoot第29讲&#xff1a;SpringBoot集成MySQL - MyBatis-Plus代码自动生成 本文是SpringBoot第29讲&#xff0c;主要介绍 MyBatis-Plus代码自动生成&#xff0c;以及产生此类代码生成工具的背景和此类工具的基本实现原理。 文章目录 SpringBoot第29讲&#xff1a;SpringBo…

STM32(HAL)串口中断接收

目录 1、简介 2 基础配置 2.1.1 SYS配置 2.1.2 RCC配置 2.2 串口外设配置 2.3 项目生成 3、KEIL端程序整合 1、简介 本文对HAL串口中断函数进行介绍。 2 基础配置 2.1.1 SYS配置 2.1.2 RCC配置 2.2 串口外设配置 2.3 项目生成 3、KEIL端程序整合 首先在main.c文件中进行…

一套AI+医疗模式的医院智慧导诊系统源码:springboot+redis+mybatis plus+mysql

一套AI医疗模式的医院智慧导诊系统源码 相关技术&#xff1a; 技术架构&#xff1a;springbootredismybatis plusmysqlRocketMQ 开发语言&#xff1a;java 开发工具&#xff1a;IDEA 前端框架&#xff1a;Uniapp 后端框架&#xff1a;springboot 数 据 库&#xff1a;mys…

华为OD机试真题 JavaScript 实现【名字的漂亮度】【牛客练习题】

目录 一、题目描述二、输入描述三、输出描述四、解题思路五、JavaScript算法源码 华为OD机试 2023B卷题库疯狂收录中&#xff0c;刷题点这里 刷的越多&#xff0c;抽中的概率越大&#xff0c;每一题都有详细的答题思路、详细的代码注释、样例测试&#xff0c;发现新题目&#x…

React的UmiJS搭建的项目集成海康威视h5player播放插件H5视频播放器开发包 V2.1.2

最近前端的一个项目&#xff0c;大屏需要摄像头播放&#xff0c;摄像头厂家是海康威视的&#xff0c;网上找了一圈都没有React集成的&#xff0c;特别是没有使用UmiJS搭脚手架搭建的&#xff0c;所以记录一下。 海康威视的开放平台的API地址&#xff0c;相关插件和文档都可以下…

CUDA_CHECK(cudaFree(...))报错CUDA error 1

GPT-3.5太好用了&#xff0c;报错情况如下&#xff1a; 总结一下, 在使用cudaFree释放之前cudaMalloc()分配的GPU内存时&#xff0c;报错cuda error,最有可能的几个原因就是&#xff1a; 试图释放已经释放的gpu内存&#xff0c;在调用cudafree&#xff08;&#xff09;时确保没…

C# Solidworks二次开发:自动创建虚拟零件及使用注意事项

今天要讲的是关于在solidworks中如何自动创建虚拟零件的功能&#xff0c;也就是solidworks中插入新零件这个功能。 实现这个功能需要使用的API如下所示&#xff1a; InsertNewVirtualPart&#xff08;swFaceOrPlane1, out swcomp2&#xff09;&#xff1b; 其中这个方法中使…

【深度学习】InST,Inversion-Based Style Transfer with Diffusion Models,论文,风格迁移,实战

代码&#xff1a;https://github.com/zyxElsa/InST 论文&#xff1a;https://arxiv.org/abs/2211.13203 文章目录 AbstractIntroductionRelated WorkImage style transferText-to-image synthesisInversion of diffusion models MethodOverview ExperimentsComparison with Sty…

登月再进一步:Apollo自动驾驶的里程碑

前言 「作者主页」&#xff1a;雪碧有白泡泡 「个人网站」&#xff1a;雪碧的个人网站 「推荐专栏」&#xff1a; ★java一站式服务 ★ ★前端炫酷代码分享 ★ ★ uniapp-从构建到提升★ ★ 从0到英雄&#xff0c;vue成神之路★ ★ 解决算法&#xff0c;一个专栏就够了★ ★ 架…

spark-sql数据重复之File Output Committer问题

前言 我们先来回顾下之前介绍过的三种Committer&#xff1a;FileOutputCommitter V1、FileOutputCommitter V2、S3A Committer&#xff0c;其基本代表了整体的演进趋势。 核心代码讲解详细参照&#xff1a;Spark CommitCoordinator 保证数据一致性 OutputCommitter commitTask…

Android如何用系统签名打包应用

前言 应用使用系统签名可以在用户不需要手动授权的情况下自动获取权限。适合一些定制系统中集成apk的方案商。 步骤 需要在AndroidManifest.xml中添加共享系统进程属性&#xff1a; android:sharedUserId"android.uid.system"如下图所示&#xff1a; 找到系统定制…

C++函数模板

2023年8月2日&#xff0c;周三上午 目录 模板的分类语法模板实例化示例程序深入理解模板参数 模板的分类 模板分为函数模板和类模板。 语法 template<typename 模板参数1,...> 返回值类型 函数名(参数列表){} template是一个关键字&#xff0c;用于声明模板 <>…

MPLS虚拟专用网跨域--OptionB方案

OptionB方案 跨域VPN-OptionB中,两个ASBR通过MP-EBGP交换它们从各自AS的PE设备接收的标签VPN-IPv4路由。图中,VPN LSP表示私网隧道,LSP表示公网隧道。 跨域VPN-OptionB方案中,ASBR接收本域内和域外传过来的所有跨域VPN-IPv4路由,再把VPN-IPv4路由发布出去。但MPLS VPN的…

C++多线程环境下的单例类对象创建

使用C无锁编程实现多线程下的单例模式 贺志国 2023.8.1 一、尺寸较小的类单例对象创建 如果待创建的单例类SingletonForMultithread内包含的成员变量较少&#xff0c;整个类占用的内存空间较小&#xff0c;则可以使用如下方法来创建单例对象&#xff08;如果类的尺寸较大则不…

穷举深搜暴搜回溯剪枝(1)

一)全排列: 46. 全排列 - 力扣&#xff08;LeetCode&#xff09; 1)先画出决策树: 越详细越好&#xff0c;就是我们在进行暴力枚举这道题的过程中&#xff0c;如何不重不漏地将所有的情况全部枚举到&#xff0c;把这个思想历程给画下来&#xff0c;就可以了&#xff0c;把每一步…

PHP高级检索功能的实现以及动态拼接sql

我们学习了解了这么多关于PHP的知识&#xff0c;不知道你们对PHP高级检索功能的实现以及动态拼接sql是否已经完全掌握了呢&#xff0c;如果没有&#xff0c;那就跟随本篇文章一起继续学习吧! PHP高级检索功能的实现以及动态拼接sql。完成的功能有&#xff1a;可以单独根据一个…

k8s部署xxl-job分布式任务调度服务

一、背景 什么时候需要把xxl-job部署到k8s里 当你的java服务部署到K8S后&#xff0c;因为xxl-job的任务调度器需要对注册上来的执行器进行健康检测&#xff0c;而java服务作为执行器&#xff0c;注册地址是pod的Ip地址&#xff1b;所以&#xff0c;调度器想要访问执行器的网路…

DevExpress WPF Tree List组件,让数据可视化程度更高!(二)

DevExpress WPF Tree List组件是一个功能齐全、数据感知的TreeView-ListView混合体&#xff0c;可以把数据信息显示为REE、GRID或两者的组合&#xff0c;在数据绑定或非绑定模式下&#xff0c;具有完整的数据编辑支持。 在上文中&#xff08;点击这里回顾DevExpress WPF Tree …

JavaScript 简单实现观察者模式和发布-订阅模式

JavaScript 简单实现观察者模式和发布-订阅模式 1. 观察者模式1.1 什么是观察者模式1.2 代码实现 2. 发布-订阅模式2.1 什么是发布-订阅模式2.2 代码实现2.2.1 基础版2.2.2 取消订阅2.2.3 订阅一次 1. 观察者模式 1.1 什么是观察者模式 概念&#xff1a;观察者模式定义对象间…