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

Spring Boot与ActiveMQ Classic基于OpenWire JMS客户端的重试问题排查

问题分析与解决方案

问题原因

  1. ActiveMQ默认重试机制冲突:ActiveMQ Classic默认maxRedeliveries值为6,加上首次消费请求,总共会触发7次无间隔重试,这是你看到当前现象的直接原因。
  2. Spring Retry未生效:你在@JmsListener方法上同时添加了@Transactional,当方法抛出异常时,JMS事务会直接回滚,消息被ActiveMQ Broker重新投递,此时Spring Retry的逻辑根本不会触发——消息是被Broker重新发送给监听器,而非在同一个方法调用内执行重试。

解决方案

根据你60秒延迟、最多4次重试的需求,提供两种可行方案:

方案一:使用Spring Retry处理重试(需关闭ActiveMQ自动重试)

1. 关闭Broker端自动重投递

修改ConnectionFactory配置,禁用ActiveMQ自带的重试机制:

@Configuration
@Slf4j
public class JmsConfig {

    @Value("${jms.activemq.brokerUrl}")
    private String brokerUrl;

    @Value("${jms.activemq.user}")
    private String brokerUsername;

    @Value("${jms.activemq.password}")
    private String brokerPassword;

    @Bean
    public ConnectionFactory connectionFactory() {
        ActiveMQSslConnectionFactory factory = new ActiveMQSslConnectionFactory();
        factory.setBrokerURL(brokerUrl);
        factory.setUserName(brokerUsername);
        factory.setPassword(brokerPassword);
        factory.setTrustAllPackages(true);
        
        // 配置重投递策略,关闭Broker自动重试
        RedeliveryPolicy redeliveryPolicy = new RedeliveryPolicy();
        redeliveryPolicy.setMaximumRedeliveries(0);
        factory.setRedeliveryPolicy(redeliveryPolicy);
        
        return factory;
    }

    // 其他Bean配置不变
}

2. 调整重试与事务的作用范围

将业务逻辑抽离为单独方法,让@Retryable作用于业务方法,@JmsListener仅负责接收消息:

@JmsListener(destination = "test")
public void receiveMessage(ObjectMessage message) throws JMSException {
    LOG.info("receiveMessage started......");
    try {
        processMessage(message);
    } catch (Exception e) {
        LOG.error("最终处理失败,消息将被确认", e);
        message.acknowledge();
    }
}

@Retryable(maxAttempts = 4, backoff = @Backoff(delay = 60000),
           include = {JMSException.class, ClassCastException.class})
@Transactional
public void processMessage(ObjectMessage message) throws JMSException {
    // 原业务逻辑代码
    .......
}

@Recover
public void recover(Exception e, ObjectMessage message) throws JMSException {
    LOG.error("4次重试后仍处理失败", e);
    // 可在此处添加死信队列投递等降级逻辑
}

注意:需确保项目已引入spring-boot-starter-aop和spring-retry依赖。


方案二:直接使用ActiveMQ延迟重投递(无需Spring Retry)

如果不想依赖Spring Retry,可直接配置ActiveMQ的重投递策略实现需求:

@Bean
public ConnectionFactory connectionFactory() {
    ActiveMQSslConnectionFactory factory = new ActiveMQSslConnectionFactory();
    factory.setBrokerURL(brokerUrl);
    factory.setUserName(brokerUsername);
    factory.setPassword(brokerPassword);
    factory.setTrustAllPackages(true);
    
    RedeliveryPolicy redeliveryPolicy = new RedeliveryPolicy();
    redeliveryPolicy.setMaximumRedeliveries(3); // 重试3次,加上首次共4次
    redeliveryPolicy.setInitialRedeliveryDelay(60000); // 首次延迟60秒
    redeliveryPolicy.setRedeliveryDelay(60000); // 每次重试间隔固定60秒
    redeliveryPolicy.setUseExponentialBackOff(false); // 关闭指数退避
    factory.setRedeliveryPolicy(redeliveryPolicy);
    
    return factory;
}

然后移除@Retryable注解,由ActiveMQ Broker负责重试逻辑:

@JmsListener(destination = "test")
@Transactional
public void receiveMessage(ObjectMessage message) throws JMSException {
    LOG.info("receiveMessage started......");
    try {
        .......
    } catch (JMSException | ClassCastException e) {
        LOG.error("Error while processing the message", e);
        throw e;
    }
}

重试失败后,消息会自动进入ActiveMQ死信队列(需确保Broker已配置死信队列)。


关键注意事项

  • 禁止同时启用Spring Retry和ActiveMQ Broker重试,否则会导致重复重试逻辑,行为不可控。
  • 建议配置死信队列,避免重试失败的消息丢失,可通过ActiveMQ配置文件或连接工厂的deadLetterStrategy设置。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.22 00:31:18