如何用STOMP客户端连接Spring Boot JMS创建的ActiveMQ Artemis队列
问题
我正在学习SpringJMS和消息中间件(MOM),用ActiveMQ Artemis做实践。通过jakarta.jms.* API创建队列目标地址,比如传入IDuser12345abc时,会生成路由类型为ANYCAST的队列地址user12345abc并发送测试消息。现在想用STOMP写前端连接这个队列,但订阅jms.queue.user12345abc时会创建新的队列地址,而非连接已有的队列。已经配置了Spring后端的StompBrokerRelay,但问题依然存在。想问下是不是有概念误解?怎么用STOMP连接之前用JMS创建的队列?
创建队列的代码
public void createUserDestination(String userId) throws JMSException { queueDestination = setupConnection().createQueue("user" + userId); producer = session.createProducer(queueDestination); producer.setDeliveryMode(DeliveryMode.PERSISTENT); producer.send(session.createTextMessage("Testing queue availability")); connection.close(); log.info("successfully created group... going back to controller"); }
STOMP订阅代码
stompClient.subscribe("jms.queue.user12345abc", (message) => { receivedMessages.value.push(message.body); });
Spring配置代码
public void configureMessageBroker(MessageBrokerRegistry registry) { // these two end points are prefixes for where the messages are pushed to registry.enableStompBrokerRelay("jms.topic", "jms.queue") .setRelayHost("127.0.0.1") .setRelayPort(61613) .setSystemLogin(brokerUsername) .setSystemPasscode(brokerPassword) .setClientLogin(brokerUsername) .setClientPasscode(brokerPassword); // this prefixes the end points where clients send messages registry.setApplicationDestinationPrefixes("/app", "jms.topic", "jms.queue"); // this prefixes the end points where the user's subscribe to registry.setUserDestinationPrefix("/user"); }
解答
核心概念澄清
ActiveMQ Artemis采用地址-队列分离的模型,和传统JMS的队列/主题模型有本质差异:
- 你用JMS
createQueue("user12345abc")时,Artemis会自动创建:- 名为
user12345abc的地址,路由类型为ANYCAST - 绑定到该地址的队列,名称同样是
user12345abc
- 名为
- Spring StompBrokerRelay的
jms.queue.XXX前缀,会将STOMP目标映射为JMS队列XXX。但如果映射后的队列在Artemis中不存在,默认配置下Artemis会自动创建新的地址和队列,这就是你看到“新建队列”的原因——要么之前创建的队列已被自动删除,要么映射逻辑没匹配到已有资源。
具体解决步骤
确认已有队列状态
登录Artemis控制台(默认地址http://localhost:8161),进入「Addresses」页面,检查是否存在user12345abc地址,以及对应的user12345abc队列。如果不存在,说明之前JMS创建的队列被自动删除了——可以在Artemis的broker.xml中确认auto-delete-queues=false(默认值为false,若修改过配置需核对),确保持久化队列不会随连接关闭而删除。调整STOMP目标与Spring配置
你当前的配置逻辑没问题,但可以换更直观的映射方式避免混淆:- 修改Spring配置,将Broker转发前缀改为
/queue和/topic:registry.enableStompBrokerRelay("/queue", "/topic") .setRelayHost("127.0.0.1") .setRelayPort(61613) .setSystemLogin(brokerUsername) .setSystemPasscode(brokerPassword) .setClientLogin(brokerUsername) .setClientPasscode(brokerPassword); - 前端STOMP订阅目标改为
/queue/user12345abc:
StompBrokerRelay会自动将stompClient.subscribe("/queue/user12345abc", (message) => { receivedMessages.value.push(message.body); });/queue/XXX映射为JMS队列XXX,直接匹配你之前用JMS创建的队列资源。
- 修改Spring配置,将Broker转发前缀改为
移除配置冲突项
你的Spring配置中,setApplicationDestinationPrefixes包含了jms.topic和jms.queue,这会导致客户端发送到这些前缀的消息被路由到Spring控制器,而非直接转发到Broker。虽然订阅操作不受影响,但建议移除这两个前缀避免潜在混淆:registry.setApplicationDestinationPrefixes("/app");验证账号权限
确保StompBrokerRelay使用的登录账号拥有访问user12345abc队列的权限,否则可能触发Artemis创建新的受限队列。
内容的提问来源于stack exchange,提问作者Bikathi Martin

