Spring Boot中WebSocket与Stomp内存泄漏问题及解决方法
解决Spring Boot Stomp WebSocket内存泄漏警告
问题原因
警告里提到的MessageBroker-*和clientInboundChannel-*线程,属于Spring WebSocket的Simple消息代理与客户端入站通道线程池。当Web应用停止时,这些线程未被自动销毁,导致Servlet容器(如Tomcat)检测到类加载器无法回收,触发内存泄漏警告。
解决方案
方案1:在配置类中实现销毁逻辑
修改WebSocket配置类,实现DisposableBean接口,在应用上下文销毁时手动停止消息代理和通道线程池:
@Configuration @EnableWebSocketMessageBroker public class WebSocketConfig implements WebSocketMessageBrokerConfigurer, DisposableBean { @Autowired private SimpleBrokerMessageContainer simpleBrokerMessageContainer; @Autowired private AbstractMessageChannel clientInboundChannel; @Override public void configureMessageBroker(final MessageBrokerRegistry registry) { registry.enableSimpleBroker("/topic"); registry.setApplicationDestinationPrefixes("/ws"); } @Override public void registerStompEndpoints(final StompEndpointRegistry registry) { registry.addEndpoint("/our-websocket") .setHandshakeHandler(new UserHandshakeHandler()) .withSockJS(); } @Override public void destroy() throws Exception { // 停止Simple消息代理 simpleBrokerMessageContainer.stop(); // 关闭客户端入站通道的线程池 if (clientInboundChannel instanceof ExecutorChannel) { Executor executor = ((ExecutorChannel) clientInboundChannel).getExecutor(); if (executor instanceof ExecutorService) { ((ExecutorService) executor).shutdown(); if (!((ExecutorService) executor).awaitTermination(10, TimeUnit.SECONDS)) { ((ExecutorService) executor).shutdownNow(); } } } } }
方案2:用SmartLifecycle统一管理组件生命周期
创建独立的生命周期管理类,统一处理WebSocket相关组件的启停:
@Component public class WebSocketLifecycleManager implements SmartLifecycle { private boolean running = false; @Autowired private SimpleBrokerMessageContainer simpleBrokerMessageContainer; @Autowired private AbstractMessageChannel clientInboundChannel; @Autowired private AbstractMessageChannel clientOutboundChannel; @Override public void start() { running = true; } @Override public void stop() { // 停止消息代理 simpleBrokerMessageContainer.stop(); // 关闭入站、出站通道的线程池 shutdownChannelExecutor(clientInboundChannel); shutdownChannelExecutor(clientOutboundChannel); running = false; } private void shutdownChannelExecutor(AbstractMessageChannel channel) { if (channel instanceof ExecutorChannel) { Executor executor = ((ExecutorChannel) channel).getExecutor(); if (executor instanceof ExecutorService) { ((ExecutorService) executor).shutdown(); try { if (!((ExecutorService) executor).awaitTermination(10, TimeUnit.SECONDS)) { ((ExecutorService) executor).shutdownNow(); } } catch (InterruptedException e) { Thread.currentThread().interrupt(); } } } } @Override public boolean isRunning() { return running; } }
方案3:升级Spring Boot版本
如果使用的是Spring Boot 2.1.x及更早版本,直接升级到2.2.0及以上版本。后续版本优化了WebSocket组件的生命周期管理,会自动在应用停止时销毁相关线程池,无需手动处理。
内容的提问来源于stack exchange,提问作者Alok Kumar
相关产品推荐
相关产品推荐

