RabbitMQ spring boot TTL延时消费

关于延时消费主要分为两种实现,一种是rabbitmq的TTL机制,一种是rabbitmq的插件实现。

实现一:TTL

1、设置队列的过期时间

2、设置消息的过期时间

添加相关maven依赖

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

1、设置队列过期时间实现延时消费

交换机及队列配置

代码中有四个配置,

第一个配置的exchange是用来接收已过期的队列信息并进行重新分配队列进行消费,

第二个配置的repeatTradeQueue为exchange重新分配的队列名,

第三个是将repeatTradeQueue队列与exchange交换机绑定,并指定对应的routing key,

第四个配置的就是我们要设置过期时间的队列deadLetterQueue,

配置中有三个参数,x-message-ttl为过期时间,该队列所有消息的过期时间都为配置的这个值,单位为毫秒,这里设置过期时间为3秒,x-dead-letter-exchange是指过期消息重新转发到指定交换机,也就是exchange,x-dead-letter-routing-key是该交换机上绑定的routing-key,将通过配置的routing-key分配对应的队列,也就是前面配置的repeatTradeQueue。

java 复制代码
import java.util.HashMap;
import java.util.Map;
 
import org.springframework.amqp.core.Binding;
import org.springframework.amqp.core.BindingBuilder;
import org.springframework.amqp.core.DirectExchange;
import org.springframework.amqp.core.Queue;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
 
@SpringBootApplication
public class Application {
    
    //交换机用于重新分配队列
    @Bean
    DirectExchange exchange() {
        return new DirectExchange("exchange");
    }
    
    //用于延时消费的队列
    @Bean
    public Queue repeatTradeQueue() {
        Queue queue = new Queue("repeatTradeQueue",true,false,false);
        return queue; 
    }
    
    //绑定交换机并指定routing key
    @Bean
    public Binding  repeatTradeBinding() {
        return BindingBuilder.bind(repeatTradeQueue()).to(exchange()).with("repeatTradeQueue");
    }
    
    //配置死信队列
    @Bean
    public Queue deadLetterQueue() {
        Map<String,Object> args = new HashMap<>();
        args.put("x-message-ttl", 3000);
        args.put("x-dead-letter-exchange", "exchange");
        args.put("x-dead-letter-routing-key", "repeatTradeQueue");
        return new Queue("deadLetterQueue", true, false, false, args);
    }
 
    
    public static void main(String[] args) throws Exception {
        SpringApplication.run(Application.class, args);
    }
}

配置生产者,这里生产者需要指定前面配置了过期时间的队列deadLetterQueue

java 复制代码
import java.time.LocalDateTime;
 
import org.springframework.amqp.core.AmqpTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
 
@Component
public class DeadLetterSender {
 
    @Autowired
    private AmqpTemplate rabbitTemplate;
 
 
    public void send(String msg) {
        System.out.println("DeadLetterSender 发送时间:"+LocalDateTime.now().toString()+" msg内容:"+msg);
        rabbitTemplate.convertAndSend("deadLetterQueue", msg);
    }
 
}

配置消费者,消费者监听指定用于延时消费的队列repeatTradeQueue

java 复制代码
import java.time.LocalDateTime;
 
@Component
@RabbitListener(queues = "repeatTradeQueue")
public class RepeatTradeReceiver {
    
    @RabbitHandler
    public void process(String msg) {
        System.out.println("repeatTradeQueue 接收时间:"+LocalDateTime.now().toString()+" 接收内容:"+msg);
    }
 
}

写一个简单的接口调用测试延时消费是否成功

java 复制代码
import org.springframework.beans.factory.annotation.Autowired;
 
@RestController
@RequestMapping("/rabbit")
public class RabbitTest {
 
    @Autowired
    private DeadLetterSender deadLetterSender;
 
 
    @GetMapping("/deadTest")
    public void deadTest() {
        deadLetterSender.send("队列设置过期时间测试");
    }
    
}

2、设置消息过期时间实现延时消费

先贴上配置的代码,基本配置都一样,唯一的区别是deadLetterQueue的过期时间这里不做配置,需要注意的是,因为我这里用的是同一个队列名,所以即使将队列过期时间配置删除,mq中该队列过期时间仍然还是存在的,所以需要删除该队列,启动项目时才能重新配置该队列属性,可能可以通过配置的方式重新覆盖属性配置,当然也可以保留队列过期时间的配置,当两个过期时间都存在时,消息取更小的过期时间。

java 复制代码
import java.util.HashMap;
 
@SpringBootApplication
public class Application {
    
    //用于死信队列转发的交换机
    @Bean
    DirectExchange exchange() {
        return new DirectExchange("exchange");
    }
    
    //用于延时消费的队列
    @Bean
    public Queue repeatTradeQueue() {
        Queue queue = new Queue("repeatTradeQueue",true,false,false);
        return queue; 
    }
    
    //绑定交换机并指定routing key
    @Bean
    public Binding  repeatTradeBinding() {
        return BindingBuilder.bind(repeatTradeQueue()).to(exchange()).with("repeatTradeQueue");
    }
    
    //配置死信队列
    @Bean
    public Queue deadLetterQueue() {
        Map<String,Object> args = new HashMap<>();
        args.put("x-dead-letter-exchange", "exchange");
        args.put("x-dead-letter-routing-key", "repeatTradeQueue");
        return new Queue("deadLetterQueue", true, false, false, args);
    }
 
    
    public static void main(String[] args) throws Exception {
        SpringApplication.run(Application.class, args);
    }
}

配置生产者,message的expiration就是过期时间的设置,单位也是毫秒

java 复制代码
import java.time.LocalDateTime;
 
import org.springframework.amqp.AmqpException;
import org.springframework.amqp.core.AmqpTemplate;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.core.MessagePostProcessor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
 
@Component
public class DeadLetterSender {
 
    @Autowired
    private AmqpTemplate rabbitTemplate;
 
    public void send(String msg, long times) {
        System.out.println("DeadLetterSender 发送时间:" + LocalDateTime.now().toString() + " msg内容:" + msg);
        MessagePostProcessor processor = new MessagePostProcessor() {
            @Override
            public Message postProcessMessage(Message message) throws AmqpException {
                message.getMessageProperties().setExpiration(times + "");
                return message;
            }
        };
        rabbitTemplate.convertAndSend("deadLetterQueue", (Object)msg, processor);
    }
}

消费者不变,用之前的类即可

稍微修改一下接口,设置时间为5秒

java 复制代码
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
 
import me.miaobo.mq.sender.DeadLetterSender;
 
@RestController
@RequestMapping("/rabbit")
public class RabbitTest {
 
    @Autowired
    private DeadLetterSender deadLetterSender;
    
    @GetMapping("/deadTest")
    public void deadTest() {
        deadLetterSender.send("消息设置过期时间测试",5000);
    }
}
相关推荐
用户8307196840824 小时前
Spring Boot 集成 RabbitMQ :8 个最佳实践,杜绝消息丢失与队列阻塞
spring boot·后端·rabbitmq
Java水解5 小时前
Spring Boot 视图层与模板引擎
spring boot·后端
Java水解5 小时前
一文搞懂 Spring Boot 默认数据库连接池 HikariCP
spring boot·后端
洋洋技术笔记9 小时前
Spring Boot Web MVC配置详解
spring boot·后端
初次攀爬者1 天前
Kafka 基础介绍
spring boot·kafka·消息队列
用户8307196840821 天前
spring ai alibaba + nacos +mcp 实现mcp服务负载均衡调用实战
spring boot·spring·mcp
Java水解1 天前
SpringBoot3全栈开发实战:从入门到精通的完整指南
spring boot·后端
用户8307196840822 天前
RabbitMQ vs RocketMQ 事务大对决:一个在“裸奔”,一个在“开挂”?
后端·rabbitmq·rocketmq
初次攀爬者2 天前
RocketMQ在Spring Boot上的基础使用
java·spring boot·rocketmq
花花无缺2 天前
搞懂@Autowired 与@Resuorce
java·spring boot·后端