Rabbitmq实现延时队列的方式

本文介绍了如何使用RabbitMQ的死信队列(TTL和DLX)以及延迟队列(DelayQueue插件)来处理消息,包括配置示例和发送/接收消息的方法。同时涵盖了Docker部署和使用延迟交换机的相关步骤。
摘要由CSDN通过智能技术生成

第一种方式  利用两个特性 Time to live (TTL) Dead Letter Exchanges (DLX) 来实现 也就是通过死信队列来完成

先把死信的队列 死信的交换机还有普通队列都定义出来 交换机与队列之间的关系绑定在代码中也是有注释说明

示例代码

创建死信队列在 rabbitMQ 的配置类
package com.aisile.rabbitmq.rabbitconfig;

import org.springframework.amqp.core.*;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class QueueDLX {

    //todo 死信队列名称
    public static final String QUEUEDLX_NAME = "queuedlx_name";
    //todo 死信交换机名称
    public static final String EXCHANGEDLX_NAME = "exchangedlx_name";
    //todo 普通队列名称
    public static final String QUEUE_NAME = "queue_name";


    //todo 死信队列绑定死信交换机
    @Bean(QUEUEDLX_NAME)
    public Queue queueDLX() {
        return QueueBuilder.durable(QUEUEDLX_NAME)
                             //#todo 这里是死信队列的特有特性,
                            //#todo 具有该特性才可以进行转发给交换机
                //#todo "x-dead-letter-exchange" 这个参数是固定写死的
                .withArgument("x-dead-letter-exchange", EXCHANGEDLX_NAME)
                //#todo "x-dead-letter-routing-key" 这个参数也是固定写死的
                .withArgument("x-dead-letter-routing-key", EXCHANGEDLX_NAME).build();
    }

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

    //todo 普通队列
    @Bean(QUEUE_NAME)
    public Queue QUEUE_NAME(){
        return new Queue(QUEUE_NAME,true);
    }

    //todo 死信交换机绑定普通队列
    @Bean
    public Binding bindingDLX(
            @Qualifier(EXCHANGEDLX_NAME) DirectExchange directExchange,
            @Qualifier(QUEUE_NAME)Queue queue){
        return BindingBuilder.bind(queue).to(directExchange).with(EXCHANGEDLX_NAME);
    }


}
 提供者发送消息
public void sendTTLDLX(){
        System.out.println(new Date());
        String str = "{'id' :'2'}";
        //发送消息给死信队列
        rabbitTemplate.convertAndSend(QueueDLX.QUEUEDLX_NAME, str.getBytes(), new MessagePostProcessor() {
                    @Override
                    public Message postProcessMessage(Message message) throws AmqpException {
                        //存活时间 毫秒  2分钟
                        message.getMessageProperties().setExpiration("1000");
                        return message;
                    }
                });
    }
 消费者监听消息代码
package com.aisile.rabbitmq.listener;

import com.aisile.rabbitmq.rabbitconfig.QueueDLX;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.annotation.RabbitHandler;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.messaging.handler.annotation.Payload;
import org.springframework.stereotype.Component;

import java.io.UnsupportedEncodingException;
import java.util.Date;

@Component
@RabbitListener(queues = QueueDLX.QUEUE_NAME)
public class CumMQListenerCJ {

    @RabbitHandler
    public void msg(@Payload Object msg) throws UnsupportedEncodingException {
        System.out.println(new Date());
        Message message = (Message) msg;
        String str = new String(message.getBody(), "utf-8");
        System.out.println(str);
    }

}

死信队列实现延时队列流程图 

 总结

死信队列 说白了也是一个队列 队列的规则就是 先进先出后进后出 比如说先进来的死信消息过期时间是 5 秒 后进的消息过期时间是 3 秒 第二个消息过期了 得等到第一个消息过期了之后才会被消费

第二种延迟队列(Delay Queue)模式

安装插件

RabbitMQ的官方也推出了一个插件 原生支持延迟队列效果

1. 下载插件 (可以在插件列表中下载)

下载后之后将插件上传到服务器中的一个位置 (自己要记得传到哪了)

2.复制插件到docker容器的rabbitmq容器的插件文件夹下
docker cp /root/rabbitmq_delayed_message_exchange-3.8.9-0199d11c.ez 容器id:/plugins
3.进入容器 查看是否拷贝成功 并启动插件 
docker exec -it rabbitmq bash
4. 启动插件
rabbitmq-plugins enable rabbitmq_delayed_message_exchange

 进入 rabbitMQ 页面 查看有相应的交换机类型 即可

 实例代码

配置类
package com.aisile.rabbitmq.rabbitconfig;

import org.springframework.amqp.core.*;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class QueueCJ {

    //交换机 ctrl+shift+u 将大写字母转换成小写
    public static final String CJ_EXCHANGEDLX = "cj_exchangedlx";
    //普通队列
    public static final String CJ_QUEUE = "cj_queue";

    //声明消息队列名称
    @Bean(CJ_QUEUE)
    public Queue MESSAGE_QUEUE(){
        return new Queue(CJ_QUEUE,true);
    }

    //声明 DirectExchange 交换机
    @Bean(CJ_EXCHANGEDLX)
    public DirectExchange CJ_EXCHANGEDLX(){
        return (DirectExchange)
                //与普通交换机唯一的不同就是 .delayed() 声明它是一个延迟交换机
                ExchangeBuilder.directExchange(CJ_EXCHANGEDLX).delayed().durable(true).build();
    }

    /**
     * #todo 绑定交换机和消息队列
     * @param directExchange
     * @param queue
     * @return
     */
    @Bean
    public Binding DLX_EXCHANGE_MESSAGE_QUEUE(
            @Qualifier(CJ_EXCHANGEDLX)DirectExchange directExchange,
            @Qualifier(CJ_QUEUE)Queue queue
    ){
        return BindingBuilder.bind(queue).to(directExchange).with(CJ_EXCHANGEDLX);
    }

}
 提供者(发消息的)
public void sendTTLDLX() throws UnsupportedEncodingException {
        System.out.println(new Date());
        String str = "{'id':'888'}";
        Message message = MessageBuilder.withBody(str.getBytes("utf-8"))
                .setHeader("x-delay", 10000).build();
        rabbitTemplate.convertAndSend(QueueCJ.CJ_EXCHANGEDLX,QueueCJ.CJ_EXCHANGEDLX,message);
    }

 消费者(接受消息的)

package com.aisile.rabbitmq.listener;

import com.aisile.rabbitmq.rabbitconfig.QueueCJ;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.annotation.RabbitHandler;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.messaging.handler.annotation.Payload;
import org.springframework.stereotype.Component;

import java.io.UnsupportedEncodingException;
import java.util.Date;

@Component
@RabbitListener(queues = QueueCJ.CJ_QUEUE)
public class CumMQListenerCJ {

    @RabbitHandler
    public void msg(@Payload Object msg) throws UnsupportedEncodingException {
        System.out.println(new Date());
        Message message = (Message) msg;
        String str = new String(message.getBody(), "utf-8");
        System.out.println(str);
    }

}

 总结

这个插件可以解决死信队列的先进先出限制的问题 没有了死信队列 直接是将消息发送给交换机的 该交换机可以将消息进行保存等待死亡时间到了 直接路由给队列 消费者就可以监听到消息了进行消费了

  • 7
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值