使用DeferredResult来设计异步接口

news2024/9/22 19:42:41

文章目录

    • 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异步注解时首先要确认你的sprinboot项目是否开启了异步功能,检查启动类中是否加了@EnableAsync注解

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

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打印”执行完毕“。

在这里插入图片描述

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

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

相关文章

助力618-Y的混沌实践之路 | 京东云技术团队

一、写在前面 1、混沌是什么&#xff1f; 混沌工程&#xff08;Chaos Engineering&#xff09;的概念由 Netflix 在 2010 年提出&#xff0c;通过主动向系统中引入异常状态&#xff0c;并根据系统在各种压力下的行为表现确定优化策略&#xff0c;是保障系统稳定性的新型手段。…

【简单认识rsync远程同步】

文章目录 一.rsync1、简介2.rsync应用场景3、 rsyncinotify的应用场景4、 rsynccron的应用场景 二.配置rsync备份源&#xff08;同步方式&#xff09;1.rsync同步源2.同步方式3.备份的方式 三.常用rsync命令3.配置源的两种表达 四、配置rsync实现同步1.使用ip表达式同步2.使用u…

【WebRTC---序篇】(七)RTC多人连麦方案

服务端可以选择mediasoup&#xff0c;作为SFU服务器&#xff0c;只负责转发数据 下图举例三个Client (browser或者客户端)同时加入一个房间&#xff0c;每个app同时发布一路视频和一路音频&#xff0c;并且接受来自其他app的音视频流&#xff0c;mediasoup内部的结构如下&…

Docker快速入门笔记

Docker快速入门 前言 当今软件开发领域的一股热潮正在迅速兴起&#xff0c;它融合了便捷性、灵活性和可移植性&#xff0c;让开发者们欣喜若狂。它就是 Docker&#xff01;无论你是一个初学者&#xff0c;还是一位经验丰富的开发者&#xff0c;都不能错过这个引领技术浪潮的工…

【Git】多人协作-多分支协作

文章目录 准备工作多人协作场景2-多分支协作补充&#xff1a;关于建立连接 远程分⽀删除后&#xff0c;本地依然能看到的解决办法 准备工作 在windosw环境下&#xff0c;再克隆同一个项目仓库&#xff0c;模拟一起协作开发的小伙伴 到此&#xff0c;相当于有了两个⽤⼾&#x…

344.翻转字符串+387.字符串中的第一个唯一字符

目录 一、翻转字符串 二、字符串中的第一个唯一字符 一、翻转字符串 344. 反转字符串 - 力扣&#xff08;LeetCode&#xff09; class Solution { public:void reverseString(vector<char>& s) {int start0;int end s.size()-1;while(start < end){swap(s[sta…

超详细!Jmeter性能测试

前言 性能测试是一个全栈工程师/架构师必会的技能之一&#xff0c;只有学会性能测试&#xff0c;才能根据得到的测试报告进行分析&#xff0c;找到系统性能的瓶颈所在&#xff0c;而这也是优化架构设计中重要的依据。 测试流程&#xff1a; 需求分析→环境搭建→测试计划→脚…

安装使用 StableDiffusionWebUI

安装使用 StableDiffusionWebUI 1 什么是 StableDiffusionWebUI2 如何完美运行 StableDiffusionWebUI 1 什么是 StableDiffusionWebUI StableDiffusion 并不是一个真正意义上的软件&#xff0c;它是由 Github 上一位叫 automatic1111 的开发者将 StableDiffusion 的源代码做了一…

Go语言入门:从零开始的快速指南(一)

文章目录 引言Go语言的诞生背景Go 语言的特性安装Go语言环境集成开发环境安装第一个Go程序Go 源代码的特征解读 引言 Go语言&#xff08;也称为Golang&#xff09;是一种开源的、静态类型的编程语言&#xff0c;由Google开发。它的设计目标是简单、高效、安全、并且易于学习和…

使用 Docker Compose 部署 Redis Cluster 集群,轻松搭建高可用分布式缓存

Redis Cluster&#xff08;Redis 集群&#xff09;是 Redis 分布式解决方案的一部分&#xff0c;它旨在提供高可用性、高性能和横向扩展的功能。Redis Cluster 能够将多个 Redis 节点组合成一个分布式集群&#xff0c;实现数据分片和负载均衡&#xff0c;从而确保在大规模应用场…

Nacos 下载安装教程

文章目录 事先准备下载并启动 Nacos设置 Nacos 开机自启动开放 Linux 外部访问权限访问 Nacos 管理界面附录 笔者的运行环境&#xff1a; 安装成功过的 Nacos&#xff1a; Nacos 2.2.3 安装成功过的 Java&#xff1a; Java 17.0.7 安装成功过的 Linux&#xff1a; RedHat Ent…

学习Node.js的基础知识和核心概念(全面)

Node.js&#xff0c;这个神奇的技术&#xff0c;融合了前端与后端的力量&#xff0c;让JavaScript在服务器端发挥了异乎寻常的魔力。本文将通过代码和文字解释&#xff0c;全面介绍Node.js的特点&#xff0c;从异步非阻塞I/O到强大的模块系统&#xff0c;再到丰富的包管理和事件…

计算机软件著作权登记申请表-模板

计算机软件著作权登记申请表 软件基本信息 软件全称 Xxxxx软件 软件简称&#xff08;如无则不填&#xff09; 分类号 说明:在附件图1-计算机软件分类代码表中提供的分类编号选择填写 计算机软件分类代码&#xff08;单选&#xff09; 30104 计算机软件适用的国民经济代…

C++学习day--17 二级指针、数组指针、指针数组

1、二级指针 二级指针的定义&#xff1a; 二级指针也是一个普通的指针变量&#xff0c;只是它里面保存的值是另外一个一级指针的地址 int guizi1 888; int *guizi2 &guizi1; //1 级指针&#xff0c;保存 guizi1 的地址 int **liujian &guizi2; //2 级指针&a…

操作系统使用免密登录

服务器免密登录 背景 在工作中使用密码登录有时候会出现这样或者那样的不方便&#xff0c;一是密码要输入&#xff0c;如果明文输入则不安全&#xff0c;二则一旦修改密码要重新分发到有权限的小伙伴 场景 在之前的工作中有很多场景需要免密等登录&#xff0c;使用免密带来…

Lvs missing port问题实例

我正在「拾陆楼」和朋友们讨论有趣的话题,你⼀起来吧? 拾陆楼知识星球入口 LVS相关文章链接: LVS 流程 SVS 流程 LVS extract net方法

QMLDay2:圆角按钮,关联键盘左右键,鼠标点击。状态切换控制。

QMLDay2 test1 作用&#xff1a; 圆角按钮&#xff0c;关联键盘左右键&#xff0c;鼠标点击。状态切换控制。 代码&#xff1a; import QtQuick 2.15 import QtQuick.Window 2.15 import QtQuick.Controls 2.15Window {width: 640height: 480visible: truecolor: "wh…

H.265/HEVC 速率控制

文章目录 速率控制视频编码速率控制速率控制的基本原理缓冲机制速率控制技术 H.265/HEVC 速率控制1. 目标比特分配2. 量化参数确定 速率控制 目前实际的视频编码率失真优化过程包括两部分&#xff1a;速率控制部分将视频序列分成编码单元&#xff0c;考虑编码单元的相关性通过…

C#,数值计算——t-分布(Student distribution)的计算方法与源程序

在概率论和统计学中&#xff0c;学生t-分布&#xff08;Students t-distribution&#xff09;经常应用在对呈正态分布的总体的均值进行估计。它是对两个样本均值差异进行显著性测试的学生t测定的基础。t检定改进了Z检定&#xff08;en:Z-test&#xff09;&#xff0c;不论样本数…

【PyQt实现复现框CheckBox】

PyQt实现复现框CheckBox 1 安装环境2 CtrlN&#xff0c;新建Main Window窗口&#xff0c;保存为checkBox.ui文件3 CheckBox的三种状态4 实现通用复选框的选中状态设置用户权限功能 1 安装环境 1&#xff09;Python环境安装PyQt5、PyQt-sip、PyQt5Designer、PyQt5-tools 2&…