You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Spring Boot 3.3.0中Session.CLIENT_ACKNOWLEDGE手动消息确认失效求助

Spring Boot 3.3.0 JMS手动确认失效问题解决方案

问题背景

在Spring Boot 3.3.0 + Java 21环境下,配置SimpleJmsListenerContainerFactory并设置Session.CLIENT_ACKNOWLEDGE后,JMS监听器仍自动确认消息(注释message.acknowledge()后消息仍被ActiveMQ移除),但手动编写的原生JMS API代码能正常实现手动确认逻辑。

核心原因

Spring JMS的@JmsListener普通方法在CLIENT_ACKNOWLEDGE模式下,默认会在方法成功返回后自动调用消息确认,无论开发者是否手动执行message.acknowledge()。只有通过特定配置或接口实现,才能完全手动控制消息确认时机。

解决方案

方案1:实现SessionAwareMessageListener接口

实现该接口后,Spring不会自动触发消息确认,需开发者手动调用message.acknowledge()完成确认:

  1. 编写监听器类
@Component
public class TestQueueListener implements SessionAwareMessageListener<Message> {
    private static final Logger log = LoggerFactory.getLogger(TestQueueListener.class);

    @Override
    public void onMessage(Message message, Session session) throws JMSException {
        try {
            TextMessage textMessage = (TextMessage) message;
            log.info("Received message: {}", textMessage.getText());
            // 业务处理完成后手动确认,注释此代码则消息不会被移除
            // message.acknowledge();
        } catch (Exception e) {
            log.error("Message processing failed", e);
            // 异常时恢复会话,触发消息重新投递
            session.recover();
        }
    }
}
  1. 配置监听器容器
@Bean
public DefaultMessageListenerContainer testQueueContainer(ConnectionFactory connectionFactory, TestQueueListener listener) {
    DefaultMessageListenerContainer container = new DefaultMessageListenerContainer();
    container.setConnectionFactory(connectionFactory);
    container.setDestinationName("test.queue");
    container.setMessageListener(listener);
    container.setSessionAcknowledgeMode(Session.CLIENT_ACKNOWLEDGE);
    container.setSessionTransacted(false);
    return container;
}

方案2:配置容器禁用自动确认

使用DefaultJmsListenerContainerFactory替代SimpleJmsListenerContainerFactory,关闭会话关闭时的自动确认逻辑:

  1. 修改容器工厂配置
@Bean
JmsListenerContainerFactory<?> jmsListenerContainerFactory(ConnectionFactory connectionFactory) {
    DefaultJmsListenerContainerFactory factory = new DefaultJmsListenerContainerFactory();
    factory.setConnectionFactory(connectionFactory);
    factory.setSessionAcknowledgeMode(Session.CLIENT_ACKNOWLEDGE);
    factory.setSessionTransacted(false);
    // 禁用会话关闭时的自动确认,完全由手动调用控制
    factory.setAcknowledgeOnSessionClose(false);
    return factory;
}
  1. 保持原@JmsListener方法不变
@JmsListener(destination = "test.queue", containerFactory = "jmsListenerContainerFactory")
public void configure(Message message) {
    try {
        TextMessage textMessage = (TextMessage) message;
        log.info("Received message {} ", textMessage.getText());
        // 仅当调用此方法时,消息才会被确认移除
        // message.acknowledge();
    } catch (Exception e) {
        log.error("Message processing failed.", e);
    }
}

额外检查项

  • 确保application.properties/yml中未覆盖ack模式配置:
    # 避免Spring Boot自动配置覆盖手动设置
    spring.jms.acknowledge-mode=client
    
  • 检查项目中是否存在其他同名的JmsListenerContainerFactory Bean,避免容器注入错误。

内容的提问来源于stack exchange,提问作者Bharad

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.17 12:45:04