RabbitMQ消息队列之实现延时队列

1、方式一:利用Time To Live(TTL)和Dead Letter Exchanges(DLX)

TTL是指消息的生存时间,RabbitMQ可以针对队列设置x-expires或者针对消息设置x-message-ttl来控制消息的生存时间。如果消息超时,则变为dead letter(死信)。DLX是指当队列中出现dead letter时,可以重新路由转发到指定的队列。

具体步骤如下:

  1. 在pom.xml文件中添加RabbitMQ的依赖。
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-amqp</artifactId>
</dependency>

    2.创建立即消费队列和延时队列例子。

@Configuration
public class RabbitMqConfig {

 
    @Bean
    public TopicExchange synCancelOrderDelayExchange(){
        TopicExchange topicExchange = new TopicExchange(RabbitConsts.X_DEAD_LETTER_EXCHANGE,true,false);
        return topicExchange;
    }

    @Bean
    public Queue synCancelOrderDelaySendQueue() {
        /**
         durable="true" 持久化 rabbitmq重启的时候不需要创建新的队列
         auto-delete 表示消息队列没有在使用时将被自动删除 默认是false
         exclusive  表示该消息队列是否只在当前connection生效,默认是false
         */
        Map<String, Object> params = new HashMap<>();
        // x-dead-letter-exchange 声明了队列里的死信转发到的DLX名称,
        params.put(RabbitConsts.X_DEAD_LETTER_EXCHANGE, RabbitConsts.X_DEAD_LETTER_EXCHANGE);
        // x-dead-letter-routing-key 声明了这些死信在转发时携带的 routing-key 名称。
        params.put(RabbitConsts.X_DEAD_LETTER_ROUTING_KEY,RabbitConsts.X_DEAD_LETTER_ROUTING_KEY);
        return new Queue(RabbitConsts.CANCELORDER_QUEUE, true, false, false,params);
    }

    /**
     普通队列
     */
    @Bean
    public Queue synCancelOrderDelayConsumeQueue() {
        /**
         durable="true" 持久化 rabbitmq重启的时候不需要创建新的队列
         auto-delete 表示消息队列没有在使用时将被自动删除 默认是false
         exclusive  表示该消息队列是否只在当前connection生效,默认是false
         死信队列里的消息过期后会转到该队列中
         */
        return new Queue(RabbitConsts.CANCELORDER_CONSUME_QUEUE, true, false, false);
    }

    /**
     将消息队列1和交换机进行绑定
     */
    @Bean
    public Binding bindingCancelOrderSend() {
        return BindingBuilder.bind(synCancelOrderDelaySendQueue()).to(synCancelOrderDelayExchange()).with(RabbitConsts.CANCELORDER_SEND_ROUTINGKEY);
    }

    /**
     * 将消息队列2和交换机进行绑定
     */
    @Bean
    public Binding bindingCancelOrderConsume() {
        return BindingBuilder.bind(synCancelOrderDelayConsumeQueue()).to(synCancelOrderDelayExchange()).with(RabbitConsts.X_DEAD_LETTER_ROUTING_KEY);
    }
   
}

 3. 启动后查看RabbitMQ服务器创建好的队列:

  4.创建消息生产者例子。

package com.jzy.service.rabbit.provider;

import com.jzy.consts.RabbitMqConstant;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.core.MessageBuilder;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.stereotype.Component;

import java.nio.charset.StandardCharsets;

@Component
@Slf4j
@RequiredArgsConstructor
public class RabbitMQSendMsgServiceV3 {

    private final RabbitTemplate rabbitTemplate;

    public void sendMsg() {
        try {
            Message msg = MessageBuilder.withBody(("哈哈呼呼呼哈哈").getBytes(StandardCharsets.UTF_8)).build();
            rabbitTemplate.convertAndSend(
                    RabbitMqConstant.EXCHANGE_RETRY_SEND_MSG, RabbitMqConstant.RETRY_SEND_MSG_ROUTING_KEY,
                    msg , message -> {
                        //设置延迟时间5000毫秒
                        message.getMessageProperties().setDelay(5000);
                        return message;
                    });
            log.info("消息发送成功");
        } catch (Exception e) {
            e.printStackTrace();
            log.error("发送消息出现异常", e);
        }

    }


}

   5.消息消费者事例:

package com.jzy.service.rabbit.consumer;

import com.jzy.consts.RabbitMqConstant;
import com.rabbitmq.client.Channel;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.core.MessageProperties;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Component;


/**
 * 监听设备端没有回复的数据
 */
@Component
@Slf4j
public class MqttRecordMessageListener {
    @RabbitListener(queues= RabbitMqConstant.QUEUE_RETRY_DELAY_SEND_MSG)
    public void listenerMessage(Message message, Channel channel){
        try {
            MessageProperties messageProperties = message.getMessageProperties();
            //接受发送的json数据
            String string = new String(message.getBody());
            log.info("这是监听到的数据----->:{}",string);
            //手动确认机制
            channel.basicAck(messageProperties.getDeliveryTag(),true);
        }catch (Exception e){
            e.printStackTrace();
            log.error("监听MQ队列出现异常。,异常信息为:",e);
        }
    }

}

2、方式二:利用RabbitMQ插件x-delay-message

RabbitMQ提供了一个插件x-delay-message,可以实现延时消息的发送和消费。

具体步骤如下:

2.1.在配置类中定义延迟交换机,设置自定义参数定义交换机类型和申明交换机中的消息为延迟消息。

package com.jzy.service.rabbit.config;

import com.jzy.consts.RabbitMqConstant;
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.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

/**
 * 消息队列整合
 */
@Configuration
public class RabbitMqConfig {

    /**
     * 队列名称
     * @return
     */
    @Bean
    public Queue sendMsgQueue() {
        return new Queue(RabbitMqConstant.QUEUE_RETRY_DELAY_SEND_MSG,true,false,false);
    }

    //Direct交换机 起名:TestDirectExchange

    /**
     * 交换机
     * String name, boolean durable, boolean autoDelete
     * @return
     */
    @Bean
    DirectExchange sendMsgExchange() {
        DirectExchange directExchange = new DirectExchange(RabbitMqConstant.EXCHANGE_RETRY_SEND_MSG, true, false);
        //开启延时队列
        directExchange.setDelayed(true);
        return directExchange;
    }

    //绑定  将队列和交换机绑定, 并设置用于匹配键:sendMsgRouting
    @Bean
    Binding bindingDirect() {
        return BindingBuilder.bind(sendMsgQueue()).to(sendMsgExchange()).with(RabbitMqConstant.RETRY_SEND_MSG_ROUTING_KEY);
    }
}
  1. 2.2.创建延迟消息的生产者,设置消息的延时时间。
package com.jzy.service.rabbit.provider;

import com.jzy.consts.RabbitMqConstant;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.core.MessageBuilder;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.stereotype.Component;

import java.nio.charset.StandardCharsets;

@Component
@Slf4j
@RequiredArgsConstructor
public class RabbitMQSendMsgServiceV3 {

    private final RabbitTemplate rabbitTemplate;

    public void sendMsg() {
        try {
            Message msg = MessageBuilder.withBody(("哈哈呼呼呼哈哈").getBytes(StandardCharsets.UTF_8)).build();
            rabbitTemplate.convertAndSend(
                    RabbitMqConstant.EXCHANGE_RETRY_SEND_MSG, RabbitMqConstant.RETRY_SEND_MSG_ROUTING_KEY,
                    msg , message -> {
                        //设置延迟时间5000毫秒
                        message.getMessageProperties().setDelay(5000);
                        return message;
                    });
            log.info("消息发送成功");
        } catch (Exception e) {
            e.printStackTrace();
            log.error("发送消息出现异常", e);
        }

    }


}
  1. 2.3.创建延迟消息的消费者,监听延迟队列。
package com.jzy.service.rabbit.consumer;

import com.jzy.consts.RabbitMqConstant;
import com.rabbitmq.client.Channel;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.core.MessageProperties;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Component;


/**
 * 监听设备端没有回复的数据
 */
@Component
@Slf4j
public class MqttRecordMessageListener {
    @RabbitListener(queues= RabbitMqConstant.QUEUE_RETRY_DELAY_SEND_MSG)
    public void listenerMessage(Message message, Channel channel){
        try {
            MessageProperties messageProperties = message.getMessageProperties();
            //接受发送的json数据
            String string = new String(message.getBody());
            log.info("这是监听到的数据----->:{}",string);
            //手动确认机制
            channel.basicAck(messageProperties.getDeliveryTag(),true);
        }catch (Exception e){
            e.printStackTrace();
            log.error("监听MQ队列出现异常。,异常信息为:",e);
        }
    }

}

完结:前面有rabbitMQ基础知识篇:RabbitMQ消息队列重要知识点:基础篇:-CSDN博客

  • 15
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

xiaolong_gogo

你的认可是我最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值