热门搜索:和平精英 原神 街篮2 

您的位置:首页 > > 教程攻略 > ai教程 >【踩坑经验】Spring Webflux 的优雅关闭(Graceful Shutdown)

【踩坑经验】Spring Webflux 的优雅关闭(Graceful Shutdown)

来源:互联网 更新时间:2026-06-15 07:42

### 背景 最近上手 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 Source Code - Reactor Netty 0.8.8 Source Code - Netty 4.1.36 Source Code

热门手游

手机号码测吉凶
本站所有软件,都由网友上传,如有侵犯你的版权,请发邮件haolingcc@hotmail.com 联系删除。 版权所有 Copyright@2012-2013 haoling.cc