调用JMS MessageListenerContainer.stop()后订阅者计数未下降问题
解决JMS非持久化Topic取消订阅后计数未减少的问题
1. 仅调用stop()不足以彻底释放订阅资源
DefaultJmsListenerContainer的stop()方法只是暂停消息监听逻辑,但不会销毁容器实例,也不会主动关闭底层的JMS会话、连接资源。这些未释放的资源会让JMS服务端判定订阅者仍处于活跃状态。
你需要在stop()之后补充调用容器的destroy()方法,彻底销毁容器并释放所有关联的JMS资源,同时从注册表中移除容器避免内存泄漏:
public void close() { JmsListenerContainer container1 = jmsListenerEndpointRegistry.getListenerContainer(uuidStream1); JmsListenerContainer container2 = jmsListenerEndpointRegistry.getListenerContainer(uuidStream2); container1.stop(); container1.destroy(); container2.stop(); container2.destroy(); jmsListenerEndpointRegistry.unregisterListenerContainer(container1); jmsListenerEndpointRegistry.unregisterListenerContainer(container2); logger.info("stream1 isRunning? " + container1.isRunning()); logger.info("stream2 isRunning? " + container2.isRunning()); }
2. 检查ListenerContainerFactory的缓存配置
如果你的pubsubNonDurableJmsListenerContainer工厂配置了CACHE_CONNECTION或CACHE_SESSION这类高缓存级别,容器停止后,连接、会话会被缓存复用,不会立即关闭,导致服务端订阅计数无法更新。
建议在工厂配置中禁用缓存,确保资源能及时释放:
@Bean(name = "pubsubNonDurableJmsListenerContainer") public DefaultJmsListenerContainerFactory pubsubNonDurableJmsListenerContainerFactory(ConnectionFactory connectionFactory) { DefaultJmsListenerContainerFactory factory = new DefaultJmsListenerContainerFactory(); factory.setConnectionFactory(connectionFactory); factory.setPubSubDomain(true); factory.setCacheLevelName("CACHE_NONE"); // 禁用缓存,强制停止时释放所有资源 return factory; }
3. 确认JMS提供者的非持久订阅机制
不同JMS提供者(如ActiveMQ、RabbitMQ JMS实现)对非持久订阅的清理逻辑存在差异。比如ActiveMQ中,非持久订阅会在会话关闭后自动移除,但如果会话被容器缓存,就不会触发清理。要确保容器配置能让会话在停止时被彻底关闭。
4. 修正代码中的拼写错误
你的代码里存在两处拼写错误:stream1TopicEndPoint、stream2TopicEndPoint应该为stream1TopicEndpoint、stream2TopicEndpoint,虽然这不会直接导致订阅计数问题,但会引发编译错误,建议优先修正。
内容的提问来源于stack exchange,提问作者Col
相关产品推荐
相关产品推荐

