Spring Boot 2.7优雅关闭时SSE连接未终止,如何通过钩子处理?
Spring Boot 2.7优雅关闭时主动终止SSE连接的解决方案
你遇到的问题是因为SSE长连接属于活跃请求,Tomcat在优雅关闭时会等待这类连接自行结束,但SSE通常是永久连接,最终触发超时并终止优雅关闭流程。@PreDestroy无法解决该问题,因为它的执行时机在上下文销毁阶段,此时优雅关闭的等待阶段已经结束。
以下是可行的解决方法:
方法一:监听ContextClosedEvent主动关闭所有SSE连接
Spring的ContextClosedEvent会在优雅关闭流程启动时触发(早于Bean销毁阶段),我们可以利用这个事件主动终止所有活跃的SSE连接:
- 创建SSE连接管理器:维护所有活跃的
SseEmitter实例,同时自动清理失效连接
@Component public class SseConnectionManager { private final List<SseEmitter> activeEmitters = new CopyOnWriteArrayList<>(); public void addEmitter(SseEmitter emitter) { activeEmitters.add(emitter); // 注册回调,自动移除已完成/超时的连接 emitter.onCompletion(() -> activeEmitters.remove(emitter)); emitter.onTimeout(() -> activeEmitters.remove(emitter)); } public void closeAllEmitters() { activeEmitters.forEach(emitter -> { try { // 主动标记连接完成,客户端会收到结束信号 emitter.complete(); } catch (Exception ignore) { // 忽略关闭时的异常,比如连接已被客户端断开 } }); activeEmitters.clear(); } }
- 注册上下文关闭事件监听器:在关闭开始时调用管理器的关闭方法
@Component public class SseShutdownListener implements ApplicationListener<ContextClosedEvent> { private final SseConnectionManager connectionManager; public SseShutdownListener(SseConnectionManager connectionManager) { this.connectionManager = connectionManager; } @Override public void onApplicationEvent(ContextClosedEvent event) { // 优雅关闭启动时,立即关闭所有SSE长连接 connectionManager.closeAllEmitters(); } }
- 在SSE接口中使用管理器:创建
SseEmitter时加入管理器
@RestController @RequestMapping("/sse") public class SseController { private final SseConnectionManager connectionManager; public SseController(SseConnectionManager connectionManager) { this.connectionManager = connectionManager; } @GetMapping("/stream") public SseEmitter stream() { SseEmitter emitter = new SseEmitter(); connectionManager.addEmitter(emitter); // 这里添加你的SSE消息发送逻辑,省略 return emitter; } }
配置完成后,触发优雅关闭时ContextClosedEvent会立即触发,管理器主动关闭所有SSE连接,Tomcat检测不到活跃请求后会直接完成优雅关闭,不会等待超时。
方法二:缩短Tomcat优雅关闭超时时间(可选)
如果仅需缩短等待时长而非主动关闭连接,可以在application.properties中配置:
server.tomcat.graceful-shutdown-timeout=5s
但这种方法只是减少等待时长,不如主动关闭彻底,因为SSE连接不会自行终止,仍会等到超时才结束。
内容的提问来源于stack exchange,提问作者gotson
相关产品推荐
相关产品推荐

