来源:互联网 更新时间:2026-06-15 07:42
### 根因 & 解法
跳过冗长的分析过程,直接说结论: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 《Off Campus》第二季官宣:这对CP还在,但不再是主角
和平精英如何做到压枪稳-和平精英怎样才能压枪稳
客单价碾压宝马奥迪!极氪5月交付新车34377辆:连续4个月双增长
免费影视剧APP推荐
HBO 奇幻剧《龙之家族》第三季定档 6 月 22 日,最终预告片曝光喉道海战
DOTA2 TI时隔七年重返上海!门票6月10日开抢,国服享受优先购买!
网络热词聊污是什么意思
帅气继父网名女生可爱英文(精选100个)
抖音最火沙雕男生网名(精选100个)
蒙古上单是什么梗
免费看电影的软件推荐
韦一敏是什么梗
金铲铲之战s17六暗星卡莎阵容玩法构筑指南
SpaceX狂揽AI人才,马斯克亲自面试且不看简历背景
作家助手如何上传自制封面 作家助手如何设置小说的封面
阿里发布Qwen3.7-Max大模型,全球第五、国产第一
有寓意的易经网名男生(精选100个)
韩漫小少爷网名大全女生(精选100个)
美国市场:股票相对债券的风险溢价正在消失
动漫《情色漫画老师OVA》剧情介绍
手机号码测吉凶
本站所有软件,都由网友上传,如有侵犯你的版权,请发邮件haolingcc@hotmail.com 联系删除。 版权所有 Copyright@2012-2013 haoling.cc