Java 中的 ResponseBodyEmitter:详解与实战

Java 中的 ResponseBodyEmitter:详解与实战

前言

在开发高并发应用或处理长时间任务时,服务端需要向客户端实时推送数据,而不是一次性将所有结果返回。Spring 提供了一种优雅的解决方案:ResponseBodyEmitter。它适用于需要逐步发送响应数据的场景,比如进度条更新、实时日志输出、消息流等。本文将深入讲解 ResponseBodyEmitter 的核心概念、使用场景、完整示例以及注意事项,帮助初学者快速掌握其使用方法。


什么是 ResponseBodyEmitter?

ResponseBodyEmitter 是 Spring MVC 提供的一个类,用于实现服务端向客户端分块推送响应数据。它是异步非阻塞的,可以在响应未完成时多次向客户端发送部分数据,而无需等待任务完成。

特性

  1. 异步非阻塞:支持异步任务,可以有效提高服务端吞吐量。
  2. 实时性:能够逐步将数据推送给客户端,适用于实时数据更新场景。
  3. 兼容性:基于标准的 HTTP 协议,客户端无需特殊支持。

ResponseBodyEmitter 的基本用法

核心方法

  1. send(Object data):向客户端发送数据,可以多次调用。
  2. complete():结束响应流,表示数据发送完毕。
  3. onTimeout(Runnable callback):设置超时回调函数。
  4. onCompletion(Runnable callback):设置完成回调函数。

典型使用场景

  1. 实时日志输出:将长时间运行任务的日志实时返回给客户端。
  2. 进度条更新:在任务执行过程中动态更新任务进度。
  3. 数据流式加载:用于大数据分片加载,比如分页查询实时返回结果。

实战:实现一个实时推送的示例

下面我们通过一个完整的例子,演示如何使用 ResponseBodyEmitter 实现任务进度实时推送功能。

示例代码

1. 创建 Controller
@RestController
@RequestMapping("/api/progress")
public class ProgressController {@GetMapping("/start")public ResponseBodyEmitter startTask() {// 创建一个 ResponseBodyEmitter 实例ResponseBodyEmitter emitter = new ResponseBodyEmitter();// 模拟一个耗时任务new Thread(() -> {try {for (int i = 1; i <= 100; i += 10) {// 向客户端发送进度emitter.send("Progress: " + i + "%\n");Thread.sleep(1000); // 模拟任务耗时}emitter.complete(); // 任务完成,关闭连接} catch (Exception e) {emitter.completeWithError(e); // 出现异常时通知客户端}}).start();return emitter; // 返回 Emitter}
}
2. 测试接口

可以使用 Postman、浏览器或客户端代码调用接口:
URL: http://localhost:8080/api/progress/start

客户端会逐步接收到如下响应:

Progress: 10%
Progress: 20%
Progress: 30%
...
Progress: 100%

深入分析

ResponseBodyEmitter 工作原理

  1. 服务端异步生成响应数据:任务执行时,调用 send() 方法将数据推送至客户端。
  2. 分块传输:数据以 HTTP 的**分块编码(Chunked Encoding)**方式传输,不会提前设置 Content-Length,而是分段发送数据块。
  3. 连接生命周期:通过 complete()completeWithError() 控制连接的关闭。

重要注意事项

  1. 支持的客户端:大多数浏览器和 HTTP 客户端库支持分块传输,但某些老旧的客户端可能不支持。
  2. 超时设置:为了避免长连接占用资源,可以为 ResponseBodyEmitter 设置超时时间:
    emitter.onTimeout(() -> emitter.complete());
    
  3. 线程安全ResponseBodyEmittersend() 方法是线程安全的,但需要注意控制任务线程的生命周期。
  4. 连接关闭:需要确保任务结束时调用 complete()completeWithError(),否则可能导致资源泄露。

扩展:与 Streaming 和 SSE 的对比

  • Streaming:直接通过 OutputStream 向客户端写入数据,灵活性高,但需手动处理流的关闭。
  • Server-Sent Events (SSE):基于 text/event-stream,适用于服务端事件推送,客户端需支持 SSE。
  • ResponseBodyEmitter:更通用,适用于任何支持 HTTP 的客户端,且易于与 Spring 集成。

总结

ResponseBodyEmitter 是 Spring 提供的轻量级流式传输解决方案,能有效提升高并发和实时性场景的用户体验。通过本文的讲解和示例,相信大家已经掌握了它的使用技巧和注意事项。在实际项目中,不妨尝试将其应用于实时日志、进度更新等场景,让你的应用更加智能、高效。


参考文档

  • Spring 官方文档
  • ResponseBodyEmitter 源码

希望这篇文章对你有所帮助!如果你有任何疑问或更好的实践经验,欢迎在评论区交流分享! 😊

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

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

相关文章

基于大数据python 房屋价格数据分析预测可视化系统(源码+LW+部署讲解+数据库+ppt)

&#xff01;&#xff01;&#xff01;&#xff01;&#xff01;&#xff01;&#xff01;&#xff01;&#xff01; 很对人不知道选题怎么选 不清楚自己适合做哪块内容 都可以免费来问我 避免后期給自己答辩找麻烦 增加难度&#xff08;部分学校只有一次答辩机会 没弄好就延迟…

pikachu文件上传漏洞通关详解

声明&#xff1a;文章只是起演示作用&#xff0c;所有涉及的网站和内容&#xff0c;仅供大家学习交流&#xff0c;如有任何违法行为&#xff0c;均和本人无关&#xff0c;切勿触碰法律底线 目录 概念&#xff1a;什么是文件上传漏洞一、客户端check二、MIME type三、getimagesi…

lua-cjson 例子

apt install -y lua-cjson 安装 编辑 tmp.lua cjson require "cjson" p 666 d "23.42" payload{"d":[{"pres":..(p)..,"temp":"..(d).."}]} print("payload " .. payload) j cjson.decode(payloa…

Monitor 显示器软件开发设计入门二

基础篇--显示驱动方案输出接口介绍 写在前面&#xff1a;首先申明&#xff0c;这篇文章是写给那些初入显示器软件行业的入门者&#xff0c;或是对显示器没有基本知识的小白人员。如您是行业大咖大神&#xff0c;可以绕行&#xff0c;可看后期进阶文章。 上篇介绍了输入接口及相…

像素流送api ue多人访问需要什么显卡服务器

关于像素流送UE推流&#xff0c;在之前的文章里其实小芹和大家聊过很多&#xff0c;不过今天偶然搜索发现还是有很多小伙伴&#xff0c;在搜索像素流送相关的问题&#xff0c;搜索引擎给的提示有这些。当然这些都是比较短的词汇&#xff0c;可能每个人真正遇到的问题和想获取的…

【21-30期】Java技术深度剖析:从分库分表到微服务的核心问题解析

&#x1f680; 作者 &#xff1a;“码上有前” &#x1f680; 文章简介 &#xff1a;Java &#x1f680; 欢迎小伙伴们 点赞&#x1f44d;、收藏⭐、留言&#x1f4ac; 文章题目&#xff1a;Java技术深度剖析&#xff1a;从分库分表到微服务的核心问题解析 摘要&#xff1a; 本…

C#里怎么样List类进行拷贝?

演示的代码: using System; using System.Collections; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace ConsoleApp1 { internal class Program { static void Main(string[] args) …

Flutter 权限申请

这篇文章是基于permission_handler 10.2.0版本写的 前言 在App开发过程中我们经常要用到各种权限&#xff0c;我是用的是permission_handler包来实现权限控制的。 pub地址&#xff1a;https://pub.dev/packages/permission_handler permission_handler 权限列表 变量 Androi…

C#:时间与时间戳的转换

1、将 DateTime 转换为 Unix 时间戳&#xff08;秒&#xff09; public static long DateTimeToUnixTimestamp(DateTime dateTime) {// 定义UTC纪元时间DateTime epochStart new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);// 计算从UTC纪元时间到指定时间的总秒数Tim…

【Spring】Spring IOCDI:架构旋律中的“依赖交响”与“控制华章”

前言 &#x1f31f;&#x1f31f;本期讲解关于Spring IOC&DI的详细介绍~~~ &#x1f308;感兴趣的小伙伴看一看小编主页&#xff1a;GGBondlctrl-CSDN博客 &#x1f525; 你的点赞就是小编不断更新的最大动力 &#x1f386;那么…

在CentOS7上更换为阿里云源

在CentOS 7上更换为阿里云YUM源可以通过以下步骤进行&#xff1a; 备份当前的YUM源配置文件 sudo mv /etc/yum.repos.d/CentOS-Base.repo /etc/yum.repos.d/CentOS-Base.repo.backup 下载阿里云的YUM源配置文件 sudo curl -o /etc/yum.repos.d/CentOS-Base.repo http://mirr…

【小白学机器学习34】基础统计2种方法:用numpy的方法np().mean()等进行统计,pd.DataFrame.groupby() 分组统计

目录 1 用 numpy 快速求数组的各种统计量&#xff1a;mean, var, std 1.1 数据准备 1.2 直接用np的公式求解 1.3 注意问题 1.4 用print() 输出内容&#xff0c;显示效果 2 为了验证公式的背后的理解&#xff0c;下面是详细的展开公式的求法 2.1 均值mean的详细 2.2 方差…

Oracle 19C Data Guard 单实例1+1部署(Duplicate方式)

环境描述 项目主库备库操作系统CentOS 7.9CentOS 7.9数据库版本Oracle 19.3.0.0Oracle 19.3.0.0ORACLE_UNQNAMEhishisdgIP地址10.172.1.10110.172.1.102Hostnamehisdb01hisdb02SIDhishisdb_namehishisdb_unique_namehishisdg 说明 主库和备库建议采用相同服务器配置。主库和…

ubuntu20配置mysql注意事项

目录 一、mysql安装 二、初始化配置密码 三、配置文件的位置 四、常用的mysql命令 五、踩坑以及解决方法 一、mysql安装 1.更新apt源 sudo apt update 2.安装mysql服务 sudo apt-get install mysql-server 3.初始化配置 sudo mysql_secure_installation 4.配置项 VALI…

开展网络安全成熟度评估:业务分析师的工具和技术

想象一下,您坐在飞机驾驶舱内。起飞前,您需要确保所有系统(从发动机到导航工具)均正常运行。现在,将您的业务视为飞机,将网络安全视为飞行前必须检查的系统。就像飞行员依赖检查表一样,业务分析师使用网络安全成熟度评估来评估组织对网络威胁的准备程度。这些评估可帮助…

MySql(面试题理解B+树原理 实操加大白话)

数据的定位 通过磁道和扇区定位到数据的位置 扇区为512字节 黄色地方数据位置为2磁道3扇区 黑色地方数据位置为1磁道1扇区 通过磁道和扇区还有偏移量定位到数据的位置 比如这里有一张表 由id、name、no、address组成id为主键 列占有大小&#xff08;字节&#xff09; id int …

目标检测,图像分割,超分辨率重建

目标检测和图像分割 目标检测和图像分割是计算机视觉中的两个不同任务&#xff0c;它们的输出形式也有所不同。下面我将分别介绍这两个任务的输出。图像分割又可以分为&#xff1a;语义分割、实例分割、全景分割。 语义分割&#xff08;Semantic Segmentation&#xff09;&…

K8s内存溢出问题剖析:排查与解决方案

文章目录 一、背景二、排查方案&#xff1a;1. 可能是数据量超出了限制的大小&#xff0c;检查数据目录大小2. 查看是否是内存溢出2.1 排查数据量&#xff08;查看数据目录大小是否超过limit限制&#xff09;2.2 查看pod详情发现问题 三、解决过程 一、背景 做redis压测过程中…

python3 + selenium 中用PIL获取全屏幕截图

获取当前屏幕截图非常简单&#xff0c;需要import PIL.ImageGrab。调用grab函数即可得到Image对象&#xff0c;显示图片如图所示。 高版本的PIL中的grab函数还提供有一些参数。要查看当前PIL包的版本&#xff0c;可以import然后查看其__version__属性。 如果是较高版本的PIL…

openssl编译安装升级为新版本

文章目录 1、下载版本2、上传并解压3、编译安装4、验证 1、下载版本 https://www.openssl.org/source/old/1.1.1/ 2、上传并解压 tar zxvf openssl-1.1.1s.tar.gz 3、编译安装 注意&#xff1a;要提前安装好 gcc perl cd openssl-1.1.1s ./config --prefix/usr/local/open…