如何将普通队列异常消息路由到死信队列

如何将普通队列异常消息路由到死信队列

在RabbitMQ中,我们经常需要处理异常消息,特别是当消息处理失败时。一个常见的用例是将异常消息路由到死信队列,以便稍后重新处理或进一步分析。在本篇博客中,我们将演示如何配置RabbitMQ和Spring Boot,以便将普通队列中的异常消息自动路由到死信队列。

步骤1:创建Spring Boot项目

首先,创建一个Spring Boot项目并添加以下依赖:

xml 复制代码
<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-amqp</artifactId>
    </dependency>
    <dependency>
        <groupId>cn.hutool</groupId>
        <artifactId>hutool-all</artifactId>
        <version>5.8.0</version>
    </dependency>
</dependencies>

步骤2:配置RabbitMQ和队列

在`application.yml文件中,配置RabbitMQ连接信息:

properties 复制代码
spring:
  #给项目来个名字
  application:
    name: rabbitmq-provider
  #配置rabbitMq 服务器
  rabbitmq:
    host: 127.0.0.1
    port: 5672
    username: root
    password: 123456
    #虚拟host 可以不设置,使用server默认host
    virtual-host: /cdn
      #确认消息已发送到交换机(Exchange)
      #确认消息已发送到队列(Queue)
    publisher-returns: true
    listener:
      simple:
        acknowledge-mode: auto
        retry:
          #enabled:开启失败重试
          enabled: true
          #第一次重试的间隔时长
          initial-interval: 1000ms
          #最长重试间隔,超过这个间隔将不再重试
          max-interval: 300000ms
          #下次重试间隔的倍数,此处是2即下次重试间隔是上次的2倍
          multiplier: 2
          max-attempts: 4
        default-requeue-rejected: false  # 达到重试次数进入死信队列
    publisher-confirm-type: none

然后,创建一个Spring组件,它将包括配置RabbitMQ队列和消息监听器:

java 复制代码
import org.springframework.amqp.core.*;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import cn.hutool.core.util.RandomUtil;

@RestController
public class ExceptionToDead {

    @Autowired
    RabbitTemplate rabbitTemplate;

    @Bean
    public Queue normalQueue() {
        return QueueBuilder.durable("my-normal-queue")
                .withArgument("x-dead-letter-exchange", "my-dead-letter-exchange")
                .withArgument("x-dead-letter-routing-key", "my-dead-letter-routing-key")
                .build();
    }

    @Bean
    public DirectExchange normalExchange() {
        return new DirectExchange("my-normal-exchange");
    }

    @Bean
    public Binding normalBinding(Queue normalQueue, DirectExchange normalExchange) {
        return BindingBuilder.bind(normalQueue).to(normalExchange).with("my-normal-routing-key");
    }

    @Bean
    public DirectExchange deadLetterExchange() {
        return new DirectExchange("my-dead-letter-exchange");
    }

    @Bean
    public Queue deadLetterQueue() {
        return QueueBuilder.durable("my-dead-letter-queue").build();
    }

    @Bean
    public Binding deadLetterBinding(Queue deadLetterQueue, DirectExchange deadLetterExchange) {
        return BindingBuilder.bind(deadLetterQueue).to(deadLetterExchange).with("my-dead-letter-routing-key");
    }

    @RabbitListener(queues = "my-normal-queue")
    public void receiveFromNormalQueue(Integer message) {
        System.out.println("正常队列收到消息: " + message);
        if (message % 2 == 0) {
            int a = 1 / 0; // 引发异常
        }
    }

    @RabbitListener(queues = "my-dead-letter-queue")
    public void receiveFromDeadLetterQueue(Integer message) {
        System.out.println("死信队列收到消息: " + message);
    }

    @GetMapping("send")
    public void send() {
        int number = RandomUtil.randomInt(0, 100);
        rabbitTemplate.convertAndSend("my-normal-exchange", "my-normal-routing-key", number);
    }

    @GetMapping("b")
    public void b() {
        int number = RandomUtil.randomInt(0, 100);
        rabbitTemplate.convertAndSend("simple-key", number);
    }
}

在这段代码中,我们创建了一个名为my-normal-queue的队列,它将异常消息路由到my-dead-letter-exchange交换机,然后再路由到my-dead-letter-queue队列。我们还创建了相应的交换机和绑定。

注意: 自动确认的时候 ,达到重试次数之后就会路由到绑定的死信,否则消息会丢失

​ 手动确认的时候,消费时候在需要的位置channel.basicNack(message.getMessageProperties().getDeliveryTag(),false,false); 消息才会路由到死信,否则消息会积压

步骤3:监听异常消息并触发死信路由

在上述代码中,我们使用@RabbitListener注解来监听my-normal-queue队列。当消息处理失败时(在这里,我们模拟了一个条件,如果消息为偶数,则引发异常),它将被路由到死信队列。

步骤4:触发异常消息

最后,我们在/send端点上创建了一个HTTP请求,它将发送一个随机整数到my-normal-queue队列。如果随机整数

相关推荐
ZZHow102436 分钟前
Java项目-苍穹外卖_Day2
java·spring boot·web
Cisyam40 分钟前
使用Bright Data API轻松构建LinkedIn职位数据采集系统
后端
float_六七40 分钟前
Spring Boot 3为何强制要求Java 17?
java·spring boot·后端
bobz9651 小时前
ovs arp
后端
_風箏1 小时前
SpringBoot【集成ElasticSearch 01】2种方式的高级客户端 RestHighLevelClient 使用(依赖+配置+客户端API测试源码
后端
用户21411832636021 小时前
dify案例分享-零基础上手 Dify TTS 插件!从开发到部署免费文本转语音,测试 + 打包教程全有
后端
架构师沉默2 小时前
Java 开发者别忽略 return!这 11 种写法你写对了吗?
java·后端·架构
EndingCoder2 小时前
React 19 与 Next.js:利用最新 React 功能
前端·javascript·后端·react.js·前端框架·全栈·next.js
RainbowJie12 小时前
Gemini CLI 与 MCP 服务器:释放本地工具的强大潜力
java·服务器·spring boot·后端·python·单元测试·maven
ITMan彪叔2 小时前
Nodejs打包 Webpack 中 __dirname 的正确配置与行为解析
javascript·后端