游乐游手机版
首页/AI教程/文章详情

Spring Webflux优雅关闭踩坑经验分享

时间:2026-06-15 15:44
SpringWebFlux在SpringBoot2 1 5与ReactorNetty0 8 8中优雅关闭失效,因disposeLater()仅调用subscribe()未阻塞,导致未完成请求被中断。通过反射获取LoopResources并注册关闭钩子,显式调用block()等待最多20秒,确保请求完成。
原始文章内容(含 HTML 与图片)已按 SEO 优化要求重写,仅修改纯文本部分,保持所有标签、属性、结构不变。 ### 背景 近期在实际项目中体验 Spring WebFlux 的“优雅关闭”功能时,发现官方文档的描述与真实表现存在偏差。实验环境基于 Spring Boot 2.1.5 与 Reactor Netty 0.8.8,当服务器仍有未完成的请求(例如一个 sleep 10 秒的接口)时,直接返回了 `Empty reply` 错误,未能实现预期的平滑关闭。 \ ### 根因与解决方案 跳过冗长的分析过程,直接给出结论:Netty 本身确实提供了 graceful shutdown 机制,并且在关闭时也的确被调用了。问题根源在于 Reactor Netty 的内部调用方式。其源码处理如下: ```ja va //reactor.netty.resources.LoopResources#dispose @Overide default void dispose() { //noop default disposeLater().subscribe(); } ``` 关键问题就在这里:`disposeLater()` 返回的是一个 `Publisher` 对象,后续直接通过 `subscribe()` 触发,并未调用 `block()` 等待其完成。因此当 Spring 的 shutdown 流程推进到后续阶段时,该异步操作被强制中断,导致未处理完的请求直接断开连接。 针对 WebFlux 体系还不算特别熟悉的情况下,暂时未找到优雅等待所有 `subscribe` 完成的标准方法,因此采用了一种相对“直接”的处理方式:在启动后通过反射获取内部的 `HttpResources`,并注册一个关闭钩子,在其中显式调用 `block()` 方法,最长阻塞等待 20 秒,从而确保剩余请求有机会正常返回。 ```ja va /** * @author Lambda.J * @version $Id: GracefulShutdown.ja va, v 0.1 2019-05-27 */ @Component public class GracefulShutdown { @Autowired ReactorResourceFactory reactorResourceFactory; LoopResources loopResources; // SpringBoot 2.1.5 reactor.netty.resources.LoopResources#dispose 只 subscribe 没有 block 造成没有等待关闭, // 这边手工调用,后面如果修复了直接删除就好 @PostConstruct void init() throws Exception { Field field = TcpResources.class.getDeclaredField("defaultLoops"); field.setAccessible(true); loopResources = (LoopResources) field.get(reactorResourceFactory.getLoopResources()); field.setAccessible(false); Runtime.getRuntime().addShutdownHook(new Thread(() -> { System.out.println("Graceful: block long to 20s before real shutdown!"); loopResources.disposeLater().block(Duration.ofSeconds(20)); })); } } ``` ### 相关知识 #### Spring 关闭流程 Spring 启动时会在 `org.springframework.context.support.AbstractApplicationContext#registerShutdownHook` 注册一个关闭钩子。 \ 实际的关闭流程在 `org.springframework.context.support.AbstractApplicationContext#doClose` 中实现: \ 大致执行顺序如下: 1. 发布上下文关闭事件 2. 关闭 lifecycle beans 3. 关闭 beanFactory 生成的单例 beans(NettyServer 的关闭正是在这一步骤中发生) \ 4. 关闭 BeanFactory 5. 关闭 DisposableServer 6. 移除监听器,设置上下文状态为 inactive 测试中发现,在关闭 bean 的过程中,当 `reactorServerResourceFactory` 关闭(即 `org.springframework.http.client.reactive.ReactorResourceFactory#destroy`)后,端口实际上已经关闭,但尚未响应的请求仍然可以继续响应。因此还有一个较为 hack 的方式:通过类复写改写这里的关闭逻辑,在关闭 reactorServer 之后等待一段时间。不过这种做法过于“暴力”,除非万不得已不建议采用。 \ ### 参考资料 - Netty 优雅退出机制和原理 - Spring Boot 2.1.5 源码 - Reactor Netty 0.8.8 源码 - Netty 4.1.36 源码
来源:https://developer.aliyun.com/article/704726
上一篇政务账号沦陷引发钓鱼攻击的机理与防御体系研究 下一篇创新与突破并没有想象中那么难
本站内容用于信息整理与展示,如有侵权或内容问题请及时联系处理。

相关推荐

补充同频道和同主题内容,方便继续浏览更多相关内容。

同类最新

继续查看同栏目最近更新的文章。

更多
Windows Docker Desktop RabbitMQ生产级部署完整指南
AI教程 · 2026-06-29

Windows Docker Desktop RabbitMQ生产级部署完整指南

前言 在 Windows 本地开发环境中,直接安装 RabbitMQ 确实颇为周折:需要单独配置 Erlang 运行环境、手动管理环境变量、服务启停全凭手工操作。更令人困扰的是,版本兼容冲突、端口占用、环境不一致等问题层出不穷。笔者见过不少开发者为搭建环境就得耗费整整半天时间。 相比之下,借助 Do

AI搜索重构制造业采购逻辑的阿里云企业级GEOCMS优化实践
AI教程 · 2026-06-29

AI搜索重构制造业采购逻辑的阿里云企业级GEOCMS优化实践

先分享一个切实感受。过去两年,我们与福建制造企业合作较为频繁,发现一个非常突出的现象:超过80%的企业官网,产品参数仍然存放在PDF或图片中。AI爬虫?根本无法抓取。这些企业技术实力不弱、资质证照齐全、应用案例也丰富,但在AI搜索这一全新战场上,它们几乎处于隐身状态。 一、一个正在发生的行业变化 A

阿里云Token Plan团队版功能价格与省钱购买指南
AI教程 · 2026-06-29

阿里云Token Plan团队版功能价格与省钱购买指南

阿里云百炼近期推出了名为“Token Plan 团队版”的全新服务,这一服务专为企业与开发者量身打造,定位为AI大模型订阅平台。通过引入Credits作为统一计量单位,将文本生成、图像生成等多模态AI能力纳入单一计费体系,同时无缝兼容主流AI编程工具及智能体(Agent)生态系统。其核心亮点包括:全

阿里云物联网.NET Core客户端位置信息上报
AI教程 · 2026-06-29

阿里云物联网.NET Core客户端位置信息上报

阿里云物联网平台的位置服务并非一个完全独立的功能模块。位置信息可包含二维坐标与三维坐标,而位置数据的来源本质上是借助设备属性进行上传。换言之,若要让设备上报位置,您需先将其视为一个普通属性进行处理。 1)添加二维位置数据 操作过程十分简洁。进入数据分析 → 空间数据可视化 → 二维数据,点击添加,将

年阿里云服务器选型配置与网站部署全攻略
AI教程 · 2026-06-29

年阿里云服务器选型配置与网站部署全攻略

2026年,阿里云服务器生态已高度成熟,形成了清晰的轻量应用服务器与ECS云服务器两大产品阵营。无论你是计划搭建个人博客、企业官网,还是运营电商平台、进行应用开发,基本都能找到理想的解决方案。本指南将从服务器选型、配置选择、部署流程到安全运维,系统梳理2026年最实用的操作要点,帮助你少走弯路,让网