使用JmsTemplate sendAndReceive后临时队列未删、连接会话未关闭问题
问题分析与解决方案
核心原因
- 临时队列残留:JMS临时队列的生命周期和创建它的会话绑定,只有会话关闭时,ActiveMQ才会自动回收临时队列。如果使用了
CachingConnectionFactory这类缓存会话的连接工厂,会话会被复用而不关闭,导致临时队列一直留存到应用 shutdown。 - 连接/会话未关闭:同样源于连接工厂的缓存机制,缓存的连接、会话会被复用,若配置不合理,可能导致资源无法及时释放。
解决方案
1. 调整连接工厂配置,禁用会话缓存
如果用了CachingConnectionFactory,修改配置让会话在每次操作后关闭:
@Bean public ConnectionFactory connectionFactory() { ActiveMQConnectionFactory activeMQConnFactory = new ActiveMQConnectionFactory(); activeMQConnFactory.setBrokerURL("tcp://localhost:61616"); CachingConnectionFactory cachingConnFactory = new CachingConnectionFactory(activeMQConnFactory); cachingConnFactory.setCacheConsumers(false); cachingConnFactory.setCacheProducers(false); cachingConnFactory.setSessionCacheSize(0); // 完全禁用会话缓存 return cachingConnFactory; }
如果不需要连接池/缓存,直接用原生ActiveMQConnectionFactory即可:
@Bean public ConnectionFactory connectionFactory() { ActiveMQConnectionFactory activeMQConnFactory = new ActiveMQConnectionFactory(); activeMQConnFactory.setBrokerURL("tcp://localhost:61616"); return activeMQConnFactory; }
2. 优化JmsTemplate配置
全局配置QoS和会话属性,避免业务代码中重复设置:
@Bean public JmsTemplate jmsTemplate(ConnectionFactory connectionFactory) { JmsTemplate jmsTemplate = new JmsTemplate(connectionFactory); jmsTemplate.setExplicitQosEnabled(true); jmsTemplate.setTimeToLive(10000); // 全局设置消息过期时间 jmsTemplate.setSessionAcknowledgeMode(Session.AUTO_ACKNOWLEDGE); return jmsTemplate; }
修改后业务代码可移除jmsTemplate.setTimeToLive(10000)这一行。
3. 手动控制会话与临时队列(兜底方案)
如果上述配置无效,可通过JmsTemplate.execute()手动管理会话、消费者/生产者,确保临时队列被删除:
@Override public S sendAndReceive(T request) throws JmsMessagingException { try { String destinationQueueName = getDestinationQueueName(); Message jmsResponseMessage = jmsTemplate.execute(session -> { // 创建请求消息并指定临时回复队列 Message requestMsg = getMessageCreator(request).createMessage(session); TemporaryQueue replyQueue = session.createTemporaryQueue(); requestMsg.setJMSReplyTo(replyQueue); // 发送请求 MessageProducer producer = session.createProducer(session.createQueue(destinationQueueName)); producer.setTimeToLive(10000); producer.send(requestMsg); // 接收回复 MessageConsumer consumer = session.createConsumer(replyQueue); Message responseMsg = consumer.receive(10000); // 清理资源 consumer.close(); producer.close(); replyQueue.delete(); // 手动删除临时队列 return responseMsg; }, true); // 执行后自动关闭会话 return convertJmsMessage(jmsResponseMessage); } catch (Exception e) { log.error(e.getMessage(), e); throw new JmsMessagingException(e); } }
4. 配置ActiveMQ Broker兜底清理
在ActiveMQ的activemq.xml中配置临时队列自动过期,防止极端情况下队列残留:
<broker xmlns="http://activemq.apache.org/schema/core" brokerName="localhost" dataDirectory="${activemq.data}"> <!-- 其他配置 --> <destinationPolicy> <policyMap> <policyEntries> <policyEntry queue=">" > <tempQueueExpiration>60000</tempQueueExpiration> <!-- 闲置1分钟后自动删除 --> </policyEntry> </policyEntries> </policyMap> </destinationPolicy> </broker>
内容的提问来源于stack exchange,提问作者cihad
相关产品推荐
相关产品推荐

