RabbitMQ 死信队列(DLX)

下面给你一套 SpringBoot + RabbitMQ 死信队列(DLX)完整可运行代码,包含:

  • 普通业务队列
  • 死信交换机 + 死信队列
  • 消息过期/拒绝自动进死信
  • 生产者 + 消费者示例

环境:SpringBoot 2.7+/3.x + AMQP Starter


1. pom.xml 依赖

xml 复制代码
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-amqp</artifactId>
</dependency>

2. application.yml

yaml 复制代码
spring:
  rabbitmq:
    host: localhost
    port: 5672
    username: guest
    password: guest
    listener:
      simple:
        acknowledge-mode: manual  # 手动ack

3. RabbitMQ 配置类(核心)

RabbitMQConfig.java

java 复制代码
import org.springframework.amqp.core.*;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

/**
 * 死信队列 DLX 配置
 */
@Configuration
public class RabbitMQConfig {

    // ==================== 死信交换机、队列 ====================
    public static final String DLX_EXCHANGE = "dlx.exchange";
    public static final String DLX_QUEUE = "dlx.queue";
    public static final String DLX_ROUTING_KEY = "dlx.routing.key";

    // 死信交换机
    @Bean
    public DirectExchange dlxExchange() {
        return new DirectExchange(DLX_EXCHANGE);
    }

    // 死信队列
    @Bean
    public Queue dlxQueue() {
        return QueueBuilder.durable(DLX_QUEUE).build();
    }

    // 绑定
    @Bean
    public Binding dlxBinding() {
        return BindingBuilder.bind(dlxQueue())
                .to(dlxExchange())
                .with(DLX_ROUTING_KEY);
    }

    // ==================== 业务普通队列(绑定死信) ====================
    public static final String BUSINESS_EXCHANGE = "business.exchange";
    public static final String BUSINESS_QUEUE = "business.queue";
    public static final String BUSINESS_ROUTING_KEY = "business.routing.key";

    @Bean
    public DirectExchange businessExchange() {
        return new DirectExchange(BUSINESS_EXCHANGE);
    }

    // 业务队列:绑定死信交换机
    @Bean
    public Queue businessQueue() {
        return QueueBuilder.durable(BUSINESS_QUEUE)
                // 死信交换机
                .withArgument("x-dead-letter-exchange", DLX_EXCHANGE)
                // 死信路由key
                .withArgument("x-dead-letter-routing-key", DLX_ROUTING_KEY)
                // 可选:设置队列消息TTL(演示过期进死信)
                // .withArgument("x-message-ttl", 10000)
                .build();
    }

    @Bean
    public Binding businessBinding() {
        return BindingBuilder.bind(businessQueue())
                .to(businessExchange())
                .with(BUSINESS_ROUTING_KEY);
    }
}

4. 生产者(发送消息)

DlxProducer.java

java 复制代码
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
import static com.example.config.RabbitMQConfig.*;

@Component
public class DlxProducer {

    @Resource
    private RabbitTemplate rabbitTemplate;

    /**
     * 发送普通消息
     */
    public void sendMsg(String msg) {
        rabbitTemplate.convertAndSend(
                BUSINESS_EXCHANGE,
                BUSINESS_ROUTING_KEY,
                msg
        );
    }

    /**
     * 发送带过期时间的消息(自动进死信)
     */
    public void sendExpireMsg(String msg, int ttl) {
        rabbitTemplate.convertAndSend(
                BUSINESS_EXCHANGE,
                BUSINESS_ROUTING_KEY,
                msg,
                message -> {
                    // 设置消息TTL
                    message.getMessageProperties().setExpiration(String.valueOf(ttl));
                    return message;
                }
        );
    }
}

5. 业务消费者(手动拒绝/失败进死信)

BusinessConsumer.java

java 复制代码
import com.rabbitmq.client.Channel;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.amqp.support.AmqpHeaders;
import org.springframework.messaging.handler.annotation.Header;
import org.springframework.stereotype.Component;
import static com.example.config.RabbitMQConfig.BUSINESS_QUEUE;

@Component
public class BusinessConsumer {

    @RabbitListener(queues = BUSINESS_QUEUE)
    public void consume(String msg,
                        Channel channel,
                        @Header(AmqpHeaders.DELIVERY_TAG) long tag) throws Exception {

        System.out.println("收到业务消息:" + msg);

        try {
            // 模拟业务异常
            // int i = 1 / 0;

            // 正常确认
            channel.basicAck(tag, false);
            System.out.println("正常消费成功");

        } catch (Exception e) {
            // 拒绝,并且不重回队列 → 进入死信
            channel.basicNack(tag, false, false);
            System.out.println("消费失败,进入死信队列");
        }
    }
}

6. 死信队列消费者

DlxConsumer.java

java 复制代码
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Component;
import static com.example.config.RabbitMQConfig.DLX_QUEUE;

@Component
public class DlxConsumer {

    @RabbitListener(queues = DLX_QUEUE)
    public void consumeDlx(String msg) {
        System.err.println("【死信队列收到】:" + msg);
        // 在这里做:重试、记录日志、人工介入、补偿任务
    }
}

7. 测试类

java 复制代码
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;
import javax.annotation.Resource;

@SpringBootTest
public class DlxTest {

    @Resource
    private DlxProducer producer;

    @Test
    public void test() {
        // 发送普通消息(消费异常会进死信)
        producer.sendMsg("测试死信消息");

        // 发送5秒过期消息(过期自动进死信)
        // producer.sendExpireMsg("5秒后过期进死信", 5000);
    }
}

8. 消息变成死信的 3 种场景

  1. 消息TTL过期
  2. 消费者 basicNack/reject 且 requeue=false
  3. 队列满了溢出

满足任意一个,都会自动进入你配置的 DLX 死信队列。


相关推荐
☞遠航☜3 小时前
rabbitmq 创建延迟队列
分布式·rabbitmq
REDcker3 小时前
RabbitMQ系列02 - RabbitMQ 消息模型:Broker、交换器、队列与收发路径
分布式·rabbitmq·ruby
飞Link3 小时前
LangGraph SDK 全量技术手册:分布式 Agent 集群的远程调用与编排引擎
开发语言·分布式·python·数据挖掘
杰克尼3 小时前
redis(day06-多级缓存)
redis·分布式·缓存
SPC的存折3 小时前
分布式(加一键部署脚本)LNMP-Redis-Discuz5.0部署指南-小白详细版
linux·运维·服务器·数据库·redis·分布式·缓存
七夜zippoe3 小时前
DolphinDB集群部署:从单机到分布式
分布式·wpf·单机·dolphindb·分集群
不懂的浪漫13 小时前
mqtt-plus 架构解析(六):多 Broker 管理,如何让一个应用同时连接多个 MQTT 服务
spring boot·分布式·物联网·mqtt·架构
小夏子_riotous20 小时前
openstack的使用——5. Swift服务的基本使用
linux·运维·开发语言·分布式·云计算·openstack·swift
刘~浪地球1 天前
消息队列--Kafka 生产环境最佳实践
分布式·kafka·linq