在@JmsListener中使用JmsTemplate发送JMS消息遇接收异常问题
问题:@JmsListener方法内发送JMS消息超时不投递
我在标注@JmsListener的方法内部发送JMS消息,代码示例如下:
@Autowired private JmsTemplate jmsTemplate; @JmsListener(destination = "myQueue1") public void receiveMessage(@Payload ObjectMessage message) { someWork1(); //takes few milliseconds jmsTemplate.send("myQueue2"); someWork2(); //takes a minute }
当前场景下,当该方法整体执行时长为1分钟时,myQueue2的消费者无法接收消息;若someWork2()仅耗时10-15秒,则myQueue2的消费者可成功接收消息。
当前TTL配置为:
spring.jms.template.time-to-live=36000
原因分析
首先明确:spring.jms.template.time-to-live的单位是毫秒,36000即36秒。问题核心在于事务上下文的影响:
默认情况下,@JmsListener的方法运行在事务中:
- 调用
jmsTemplate.send()时,消息并没有立即投递到myQueue2,而是暂存在当前事务的资源里 - 只有当整个
receiveMessage()方法执行完毕、事务提交后,消息才会真正被发送到队列 - 如果
someWork2()耗时1分钟,从发送消息到事务提交的间隔会超过36秒,导致消息过期,自然不会被消费者接收
解决方案
1. 调整消息TTL(最简单方案)
如果业务允许,直接把TTL调大到超过方法的最长执行时间:
spring.jms.template.time-to-live=60000 # 设置为60秒,覆盖1分钟的执行时长
2. 开启新事务发送消息(推荐)
给发送myQueue2的逻辑单独开启新事务,让消息立即提交,不受当前监听器事务的影响。可以用@Transactional(Propagation.REQUIRES_NEW):
先定义独立的消息发送服务:
@Service public class JmsSenderService { @Autowired private JmsTemplate jmsTemplate; @Transactional(propagation = Propagation.REQUIRES_NEW) public void sendToMyQueue2() { jmsTemplate.send("myQueue2", session -> { // 这里构造你的消息,示例为文本消息 return session.createTextMessage("message content"); }); } }
然后在监听器中调用这个服务:
@Autowired private JmsSenderService jmsSenderService; @JmsListener(destination = "myQueue1") public void receiveMessage(@Payload ObjectMessage message) { someWork1(); jmsSenderService.sendToMyQueue2(); // 新事务提交后,消息立即投递 someWork2(); }
3. 关闭监听器事务(谨慎使用)
如果业务不需要事务一致性,可以关闭@JmsListener的事务:
spring.jms.listener.transaction.enabled=false spring.jms.listener.acknowledge-mode=auto # 根据需求选auto或client
⚠️ 注意:这种方式会丢失事务保障,比如someWork2()执行失败时,myQueue1的消息已经被确认,无法回滚,仅适用于无事务要求的场景。
内容的提问来源于stack exchange,提问作者Hasn A
相关产品推荐
相关产品推荐

