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

Spring Boot多实例消费ActiveMQ Artemis多播队列仅单实例收消息问题

问题分析与解决方案

你的问题核心是错误地将监听器绑定到了点对点模式的队列,导致多个应用实例竞争消费消息,而非实现多播(每个实例都收到消息)。以下是具体问题点和修复方案:

问题原因

  1. 监听器目标错误:你使用@JmsListener(destination = "onboard_address::onboard_application")直接绑定到了特定队列onboard_application。ActiveMQ Artemis中,队列默认路由类型是ANYCAST(点对点),消息会轮询分配给消费者,且消费后从队列删除,因此只有一个实例能收到消息。
  2. 发送与消费模式不匹配:发送方通过pubSubDomain=true以多播(Topic)模式发送消息到地址onboard_address,但监听器并未订阅该地址的多播消息,而是监听了一个绑定到该地址的点对点队列。

修复方案

方案一:使用标准JMS Topic多播(推荐)

直接让监听器订阅地址onboard_address,利用Spring配置的pub-sub-domain=true启用Topic模式,每个应用实例会自动创建独立的订阅队列,从而都能收到消息:

修改监听器代码:

@JmsListener(destination = "onboard_address")
public void applicationOnboardingMessageReceiver(String message) throws JsonProcessingException {
    ApplicationDTO appDTO = objectMapper.readValue(message, ApplicationDTO.class);
    //Business logic
}

如果需要持久订阅(应用重启后不丢失未消费的消息),需指定唯一的clientId和订阅ID:

// 每个应用实例的clientId必须唯一,比如通过配置文件注入
@JmsListener(destination = "onboard_address", clientId = "${jms.client-id}", subscription = "onboard_subscription")
public void applicationOnboardingMessageReceiver(String message) throws JsonProcessingException {
    ApplicationDTO appDTO = objectMapper.readValue(message, ApplicationDTO.class);
    //Business logic
}

在application.yml中为每个实例配置不同的clientId:

jms:
  client-id: app-instance-1 # 另一个实例配置为app-instance-2

方案二:修改队列路由类型为多播

如果必须保留队列名onboard_application,需在ActiveMQ Artemis的broker.xml中配置该队列的路由类型为MULTICAST,让所有订阅该队列的消费者都能收到消息:

<address name="onboard_address">
    <multicast>
        <queue name="onboard_application"/>
    </multicast>
</address>

配置完成后,你的监听器代码无需修改,两个应用实例都会收到发送到onboard_address的所有消息。

额外注意事项

  • 发送方代码中的jmsTemplate.setPubSubDomain(true)无需修改,确保消息以多播模式发送到地址onboard_address。
  • 若使用方案一,无需手动创建队列,Artemis会为每个订阅自动生成对应的持久/临时队列。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.25 14:05:08