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

Spring JMS集成Azure Service Bus发送消息至死信队列报错咨询

问题描述

我有一个Azure主题,当因任意原因无法处理事件时,需要将消息发送至Azure Service Bus死信队列,当前使用如下依赖:

<dependency>
  <groupId>com.azure.spring</groupId>
  <artifactId>spring-cloud-azure-starter-servicebus-jms</artifactId>
  <version>${azure.jms.version}</version>
</dependency>

目前我已配置JmsListenerConnectionFactory用于接收事件,同时配置了JmsTemplate Bean用于向第二个主题发布消息,上述逻辑运行正常。现我尝试配置第二个JmsTemplate Bean用于向死信队列发布消息,相关代码如下:

连接工厂构建方法:

private ServiceBusJmsConnectionFactory buildJmsConnectionFactory(String connectionString,
            String topicName) 
{
        var replacedConnectionString = connectionString.replace("sb://", "");
        var connectionFactory = new ServiceBusJmsConnectionFactory(replacedConnectionString);
        var serviceBusConnectionString = new ServiceBusConnectionString(replacedConnectionString);
        var remoteUri = String.format(AMQP_URI_FORMAT, serviceBusConnectionString.getEndpointUri(), 100000);
        connectionFactory.setRemoteURI(remoteUri);
        connectionFactory.setClientID(topicName);
        connectionFactory.setUsername(serviceBusConnectionString.getSharedAccessKeyName());
        connectionFactory.setPassword(serviceBusConnectionString.getSharedAccessKey());
        connectionFactory.setCloseTimeout(600000L);
        return connectionFactory;
    }

死信队列专用连接工厂Bean:

@Bean
public ConnectionFactory deadLetterConnectionFactory() {
    var connectionFactory = buildJmsConnectionFactory(listenerConnectionString, topicName);
    var cachingConnectionFactory = new CachingConnectionFactory(connectionFactory);
    cachingConnectionFactory.setCacheProducers(false);
    return cachingConnectionFactory;
}

死信队列专用JmsTemplate Bean:

@Bean
public JmsTemplate deadLetterJmsTemplate(@Qualifier("deadLetterPriceListConnectionFactory")
                                          ConnectionFactory connectionFactory) {
    var template = new JmsTemplate(connectionFactory);
    template.setPubSubDomain(true);
    template.setDefaultDestinationName("topicName/Subscriptions/subscriptionName/$deadletterqueue");
    return template;
}

在业务类中我调用了convertAndSend方法发送消息:

deadLetterJmsTemplate.convertAndSend("test destination dead letter");

根据Azure官方文档说明,我认为需要使用上述格式指定目的地名称,但实际运行时出现无法为订阅创建发送方、或超时的错误。
补充说明:订阅从属于对应主题。

咨询问题点:

  • 我对死信队列目的地命名格式的假设是否正确?
  • 是否需要补充其他配置或采用其他实现方式才能正确向死信队列发送消息?

问题解答

你的配置存在3处核心错误,按以下规则修改即可正常向死信队列发送消息:

  1. 修正消息域配置
    死信队列是点对点类型的队列实体,不属于发布订阅域的主题/订阅实体,你当前设置template.setPubSubDomain(true)是错误的,需要改为false,JmsTemplate会以队列模式连接死信队列,不会再触发订阅发送方创建逻辑。
  2. 修正死信队列路径格式
    路径中的死信队列节点是驼峰命名,你代码中写的全小写$deadletterqueue会导致路径匹配失败,正确路径格式为:

    {实际主题名}/Subscriptions/{实际订阅名}/$DeadLetterQueue
    注意将占位符替换为你环境中真实的主题、订阅名称,不要直接写topicName、subscriptionName字面量。

  3. 移除冗余连接工厂配置
    你给死信队列连接工厂设置了固定clientID,死信队列发送场景不需要绑定持久订阅专属客户端ID,固定客户端ID容易出现连接占用冲突,直接删除connectionFactory.setClientID(topicName);这行配置即可解决超时问题。

如果担心手写路径出现拼写错误,可以直接用Service Bus自带的工具类生成标准死信队列路径,避免人为拼写失误:

import com.azure.messaging.servicebus.EntityNameHelper;
// 生成对应订阅的标准死信队列路径
String subscriptionPath = topicName + "/Subscriptions/" + subscriptionName;
String dlqPath = EntityNameHelper.formatDeadLetterPath(subscriptionPath);
template.setDefaultDestinationName(dlqPath);

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.26 14:24:20