Spring Boot集成ActiveMQ时@JmsListener接收自身发送消息被阻塞问题咨询
问题原因
默认配置下,ActiveMQ 5 对 @JmsListener 标注的消费方法会自动开启本地事务,且 JmsTemplate 默认复用当前线程绑定的消费会话:
- 你在
onIn方法中发送的out队列消息,会被纳入当前消费会话的事务中 - 事务内的消息虽然已经同步到 Broker 端,会在管控台展示为已到达,但会被标记为未提交状态,对所有普通消费者不可见;只有当整个
onIn方法执行完成、消费事务提交后,out队列的消息才会变为可消费状态,被监听器或JmsTemplate拉取 - 为
onIn添加@Async注解后,方法会运行在独立异步线程中,发送消息时会创建全新的 JMS 会话,不受原消费事务约束,消息发送后会立即提交,因此可以被马上消费。
无需
@Async 的解决方案 方案1:关闭消费端事务(无事务需求推荐)
如果你的业务不需要消费失败自动回滚重试的事务保障,直接修改配置关闭监听器的事务开关即可:
在 application.properties 中添加配置:
spring.jms.listener.session-transacted=false spring.jms.listener.acknowledge-mode=auto
修改后消费方法不再开启事务,消息发送后立即生效,无需等待方法执行完成。
方案2:独立配置发送用非事务JmsTemplate(需保留消费事务时使用)
如果必须保留消费端的事务能力,可以单独定义一个非事务的 JmsTemplate 用于发送响应消息,避免和消费会话绑定:
import javax.jms.Session; import org.springframework.context.annotation.Bean; import org.springframework.jms.core.JmsTemplate; import javax.jms.ConnectionFactory; // SpringBoot 3.x及以上版本改为jakarta.jms.ConnectionFactory @Bean public JmsTemplate nonTransactedJmsTemplate(ConnectionFactory connectionFactory) { JmsTemplate jmsTemplate = new JmsTemplate(connectionFactory); jmsTemplate.setSessionTransacted(false); jmsTemplate.setSessionAcknowledgeMode(Session.AUTO_ACKNOWLEDGE); return jmsTemplate; }
在业务代码中注入这个自定义的 JmsTemplate 发送 out 队列消息即可,发送的消息不会被纳入消费事务,发完即可被消费者正常接收。
内容的提问来源于stack exchange,提问作者Mark Schäfer
相关产品推荐
相关产品推荐

