尧图网络 高端网站定制 · 原创设计
免费咨询热线
400-888-6620
免费获取方案
Spring Boot中使用SSE实现高效实时数据推送
1. 为什么选择SSE实现实时数据推送去年我在开发一个物流追踪系统时遇到了一个典型场景需要将快递的实时位置推送给前端页面但又不想引入复杂的WebSocket。经过技术选型对比最终选择了Server-Sent Events(SSE)方案。与WebSocket相比SSE有几个显著优势协议简单基于纯HTTP协议不需要额外的握手过程自动重连浏览器内置了重连机制轻量级特别适合单向数据推送场景兼容性好主流浏览器都支持重要提示如果你的应用需要双向通信WebSocket仍是更好的选择。但对于90%只需要服务器推送的场景SSE往往更合适。2. Spring Boot中SSE的核心实现2.1 基础环境搭建首先创建一个标准的Spring Boot项目我推荐使用Spring Initializr生成基础结构。关键依赖只需要dependency groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter-web/artifactId /dependency2.2 核心控制器实现创建一个SSE控制器这里分享我在实际项目中的最佳实践RestController RequestMapping(/sse) public class SseController { private static final MapString, SseEmitter emitters new ConcurrentHashMap(); GetMapping(/subscribe) public SseEmitter subscribe(RequestParam String clientId) { SseEmitter emitter new SseEmitter(30 * 60 * 1000L); // 30分钟超时 emitters.put(clientId, emitter); emitter.onCompletion(() - emitters.remove(clientId)); emitter.onTimeout(() - emitters.remove(clientId)); return emitter; } public static void push(String clientId, Object data) { SseEmitter emitter emitters.get(clientId); if (emitter ! null) { try { emitter.send(SseEmitter.event() .id(UUID.randomUUID().toString()) .name(message) .data(data)); } catch (IOException e) { emitter.complete(); emitters.remove(clientId); } } } }这段代码有几个关键点使用ConcurrentHashMap存储emitter实例线程安全设置了合理的30分钟超时时间实现了自动清理机制提供了静态push方法供业务调用2.3 前端对接实现前端实现非常简单现代浏览器都原生支持EventSourceconst eventSource new EventSource(/sse/subscribe?clientId123); eventSource.onmessage (event) { const data JSON.parse(event.data); console.log(收到推送:, data); }; eventSource.onerror () { console.error(连接中断将自动重连); };3. 生产环境进阶技巧3.1 性能优化方案在实际高并发场景中我总结了几个优化点连接池管理建议使用Guava的Cache替代ConcurrentHashMapLoadingCacheString, SseEmitter emitterCache CacheBuilder.newBuilder() .maximumSize(10000) .expireAfterAccess(30, TimeUnit.MINUTES) .build();心跳机制防止连接被代理服务器断开Scheduled(fixedRate 25000) public void sendHeartbeat() { emitters.forEach((id, emitter) - { try { emitter.send(SseEmitter.event().comment(heartbeat)); } catch (IOException e) { emitter.complete(); emitters.remove(id); } }); }批量推送当需要推送大量客户端时使用线程池并行处理3.2 安全防护措施认证集成可以在subscribe接口上添加Spring Security注解PreAuthorize(hasRole(USER)) GetMapping(/subscribe) public SseEmitter subscribe(RequestParam String clientId) { // ... }限流保护使用Guava RateLimiter防止DDOS攻击private final RateLimiter limiter RateLimiter.create(100); // 每秒100个请求 GetMapping(/subscribe) public SseEmitter subscribe(RequestParam String clientId) { if (!limiter.tryAcquire()) { throw new RuntimeException(请求过于频繁); } // ... }4. 常见问题排查指南4.1 连接立即断开现象前端刚建立连接就触发onerror排查步骤检查服务器是否返回了正确的Content-TypeGetMapping(value /subscribe, produces MediaType.TEXT_EVENT_STREAM_VALUE)检查是否有跨域问题添加CORS配置检查Nginx等代理服务器配置可能需要添加proxy_set_header Connection ; proxy_http_version 1.1; proxy_buffering off;4.2 消息堆积问题现象客户端接收消息延迟严重解决方案检查emitter的send方法是否阻塞使用异步发送模式CompletableFuture.runAsync(() - { try { emitter.send(event); } catch (IOException e) { // 错误处理 } });4.3 内存泄漏问题现象服务运行一段时间后内存持续增长排查方法使用JVisualVM监控emitter实例数量确保所有emitter都有onCompletion/onTimeout回调定期扫描并清理失效连接5. 实际项目应用案例以我最近开发的快递追踪系统为例SSE的典型数据格式设计{ event: location_update, data: { packageId: SF123456789, timestamp: 2023-07-20T14:30:00Z, location: { lat: 39.9042, lng: 116.4074 }, status: in_transit } }前端根据不同event类型进行相应处理eventSource.addEventListener(location_update, (e) { updateMap(JSON.parse(e.data)); }); eventSource.addEventListener(status_change, (e) { updateStatusBadge(JSON.parse(e.data)); });这种设计使得系统可以处理多种类型的实时事件而不仅限于单一数据格式。6. 监控与运维方案在生产环境中我建议添加以下监控指标活跃连接数使用Micrometer暴露指标Gauge.builder(sse.connections, emitters::size) .register(meterRegistry);消息吞吐量Counter.builder(sse.messages.sent) .tag(type, notification) .register(meterRegistry);异常监控统一处理发送异常try { emitter.send(event); } catch (IOException e) { metrics.counter(sse.errors, type, io).increment(); // ... }这些指标可以集成到PrometheusGrafana监控体系中形成完整的可视化看板。7. 扩展应用场景除了传统的实时通知SSE还可以用于实时日志推送开发环境查看应用日志股票行情推送低频更新的金融数据物联网数据监控设备状态实时展示协同编辑系统文档变更通知在Spring AI项目中SSE特别适合用于流式输出AI生成内容。例如GetMapping(/ai/generate) public SseEmitter generateContent(RequestParam String prompt) { SseEmitter emitter new SseEmitter(); aiService.generateStream(prompt, chunk - { try { emitter.send(SseEmitter.event() .data(chunk) .name(ai_chunk)); } catch (IOException e) { // 错误处理 } }); return emitter; }前端可以实时显示生成过程极大提升用户体验。
RELATED

相关推荐

轴承座零件机械加工工艺与夹具设计全流程解析

轴承座零件机械加工工艺与夹具设计全流程解析

作为一个常年泡在工艺和夹具堆里的机械工程师,看到“轴承座零件的机械加工工艺规程及夹具设计”这种题目,第一反应就是——这活儿可太经典了。轴承座这种零件在机械结构里几乎无处不在,从电机底座到传动轴支撑,你都能看到它的身影…

📅 2026/9/15 0:18:48
发动机试验台底座设计安装全攻略:从结构选型到隔振调平

发动机试验台底座设计安装全攻略:从结构选型到隔振调平

干了将近十年的发动机台架测试,我越来越确认一件事:项目的成败,往往先取决于那块最不起眼的发动机试验台底座。它没有测功机那么多参数要标定,也不像发动机电控系统那样逻辑复杂,但底座一旦设计不对、装得不稳&#xf…

📅 2026/9/15 0:18:48
AI落地:业务价值优先的架构设计原则

AI落地:业务价值优先的架构设计原则

先直接给结论:绝大部分“AI落地”项目,死在的不是算法不行,不是算力不够,而是从一开始就搞错了出发点。很多团队拿到一个AI任务,第一反应是“用哪个模型”“要不要上RAG”“怎么微调”,却很少有人先问一句&…

📅 2026/9/15 0:18:48
MORE NEWS

更多资讯

📰

UPS寿命延展:温度、电池与功率器件的主动健康管理

1. 为什么UPS寿命不是“用到坏”,而是“养到老”?很多人把UPS当成插上电就能用的黑盒子——市电正常时它默默待机,停电时“啪”一下顶上,任务就算完成。等哪天突然带不动负载、蜂鸣器狂响、面板报警灯全亮,才惊觉&…

📰

EMC工程实战:干扰源、耦合路径与敏感设备的动态平衡

1. 这不是教科书里的概念搬运,而是工程师在产线凌晨三点调不出EMC问题时的真实抓手“电磁干扰”、“敏感性”、“抗扰度”——这三个词,你可能在产品规格书里扫过一眼,在安规报告里见过几行结论,在EMC实验室门口的告示牌上瞥过一回…

📰

STM32游戏开发:恐龙跳跃与障碍躲避实现

1. 项目背景与核心设计恐龙小跳与躲避障碍游戏是嵌入式开发中经典的练手项目,特别适合在STM32这类资源有限的微控制器上实现。这个项目巧妙地将两款游戏整合到同一个系统中,通过状态机管理游戏流程,既锻炼了开发者的硬件驱动能力,…

📰

企业私有知识库构建:从文档管理到智能检索

1. 项目概述:企业私有知识库的核心价值去年为一家中型科技公司部署私有知识库时,他们的CTO向我抱怨:"每次新人入职都要花两周熟悉公司文档,老员工也经常找不到最新版技术手册。"这正是企业知识管理的典型痛点——信息孤…

📰

ArmorPaint:实时PBR纹理绘制开源工具详解

1. ArmorPaint 是什么?一个专为实时 PBR 纹理绘制而生的开源工具ArmorPaint 不是一个“又一个”3D 软件插件,也不是 Blender 里某个隐藏的着色器节点组。它是一个从零开始、完全独立、专一聚焦于实时物理材质纹理绘制(Real-time PBR Texture …

📰

OpenUI5框架初始化流程与DOM处理机制详解

1. OpenUI5框架初始化流程概览在OpenUI5框架启动过程中,initDOM.js扮演着至关重要的角色。这个文件位于OpenUI5核心库的src/sap.ui.core/src/sap/ui/dom/目录下,主要负责处理DOM相关的初始化工作。作为框架启动链路上的关键环节,它会在sap-ui…

TODAY

今日更新

THIS WEEK

本周精选

THIS MONTH

本月热门

读完文章,想聊聊您的网站?

告诉我们您的行业与需求,资深顾问一对一梳理方案与报价,全程免费。

📞 💬