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

SpringBoot ActiveMQ:JmsListenerConfigurer创建的JMS消费者非持久化

解决动态创建持久化ActiveMQ主题消费者的问题

我之前也碰到过一模一样的情况——用@JmsListener注解能轻松实现持久化主题消费,但切换到JmsListenerConfigurer动态注册监听器时,消费者就变成非持久化状态了。核心问题很明确:动态注册时需要我们手动配置持久化订阅的关键属性,而@JmsListener会帮我们自动处理这些细节。

必须配置的核心属性

要让动态创建的消费者成为持久化订阅者,这三个属性缺一不可:

  • clientId:每个持久化订阅者需要唯一的客户端ID(ActiveMQ严格要求同一个clientId不能重复注册)
  • subscriptionDurable:显式标记该订阅为持久化类型
  • 同时要确保消息监听容器工厂开启了Pub/Sub模式(pubSubDomain = true)

完整代码实现

下面是可直接复用的示例,通过JmsListenerConfigurer完成动态持久化主题消费者的创建:

import org.springframework.context.annotation.Configuration;
import org.springframework.jms.annotation.JmsListenerConfigurer;
import org.springframework.jms.config.JmsListenerEndpointRegistrar;
import org.springframework.jms.config.SimpleJmsListenerEndpoint;
import org.springframework.jms.listener.MessageListenerContainer;

import javax.jms.Message;
import javax.jms.MessageListener;

@Configuration
public class DynamicDurableTopicListenerConfig implements JmsListenerConfigurer {

    // 注入提前配置好的JmsListenerContainerFactory(需确保已开启Pub/Sub模式)
    private final JmsListenerContainerFactory<?> jmsListenerContainerFactory;

    public DynamicDurableTopicListenerConfig(JmsListenerContainerFactory<?> jmsListenerContainerFactory) {
        this.jmsListenerContainerFactory = jmsListenerContainerFactory;
    }

    @Override
    public void configureJmsListeners(JmsListenerEndpointRegistrar registrar) {
        // 创建一个简单的JMS监听端点
        SimpleJmsListenerEndpoint endpoint = new SimpleJmsListenerEndpoint();
        
        // 1. 设置唯一客户端ID(集群环境下建议结合实例ID生成,避免冲突)
        endpoint.setClientId("dynamic-durable-consumer-001");
        // 2. 标记为持久化订阅
        endpoint.setSubscriptionDurable(true);
        // 3. 设置订阅名称(可选,方便在ActiveMQ控制台管理订阅)
        endpoint.setSubscriptionName("my-durable-topic-sub");
        // 4. 指定要监听的目标主题
        endpoint.setDestination("my-business-topic");
        
        // 5. 配置消息处理逻辑
        endpoint.setMessageListener(new MessageListener() {
            @Override
            public void onMessage(Message message) {
                try {
                    // 这里编写你的消息消费业务逻辑
                    System.out.println("收到持久化主题消息:" + message.getBody(String.class));
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        });
        
        // 将端点注册到监听容器
        registrar.registerEndpoint(endpoint, jmsListenerContainerFactory);
    }
}

额外注意事项

  1. 容器工厂配置:你的JmsListenerContainerFactory必须开启Pub/Sub模式,示例配置如下:
    @Bean
    public JmsListenerContainerFactory<?> jmsListenerContainerFactory(ConnectionFactory connectionFactory) {
        DefaultJmsListenerContainerFactory factory = new DefaultJmsListenerContainerFactory();
        factory.setConnectionFactory(connectionFactory);
        // 开启Pub/Sub模式,适配主题消费
        factory.setPubSubDomain(true);
        // 持久化订阅建议设置单线程消费,避免重复消费
        factory.setConcurrency("1");
        return factory;
    }
    
  2. ClientId唯一性:如果是多实例部署,要保证每个实例的clientId唯一,比如可以结合实例的IP、端口或者容器ID动态生成。
  3. 主题自动创建:如果ActiveMQ未提前创建目标主题,需要在ActiveMQ配置中开启自动创建主题的功能(默认是开启的)。

按照上述配置完成后,动态创建的消费者就会成为持久化订阅者,即使消费者下线,ActiveMQ也会保留未消费的消息,等消费者重新上线后继续推送。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.26 08:50:30