死信队列+延时队列存在的问题
由于传统的延时队列+死信队列实现自动取消订单的延时任务一下子就需要在RabbitMQConfig文件中配置6个方法,这样会比较麻烦,而且消息消费顺序是采用先进先出的规则,不能够实现第1条消息过期时间为10分钟,第2条消息的过期时间少于第1条的存活时间,导致第二条消息不能及时消费,这个时候引入RabbitMQ的延时队列插件即可解决这两个问题。
介绍
RabbitMQ的延时队列插件采用的是过期时间到了就消费的规则,不像其他队列是根据先进先出的规则进行消费,使用延时队列插件可以完成各种各样的延时任务,比如:不同时长的会员自动过期、自动取消订单等延时任务。下面我们以自动取消订单为例,做一个demo。
一、安装
1、在windows下进行安装
1)、下载和安装
csdn下载地址:https://download.youkuaiyun.com/download/ppjsyw/85055786(无需积分即可下载)
下载完成之后将文件复制到RabbitMQ的plugins目录
2)、启用插件
先切换到RabbitMQ的sbin目录,然后输入如下命令启用插件
rabbitmq-plugins enable rabbitmq_delayed_message_exchange
之后重启RabbitMQ服务即可
二、引入依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-amqp</artifactId>
</dependency>
三、修改application.yml
server:
port: 80
spring:
rabbitmq:
host: localhost # 地址
port: 5672 # 端口号
virtual-host: / #虚拟host
username: guest # 用户名
password: guest # 密码
publisher-confirms: true #如果对异步消息需要回调必须设置为true
四、在RabbitMqConfig配置队列、交换机和路由key
package com.hq.rabbitmq.config;
import org.springframework.amqp.core.Binding;
import org.springframework.amqp.core.BindingBuilder;
import org.springframework.amqp.core.CustomExchange;
import org.springframework.amqp.core.Queue;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.util.HashMap;
/**
* @Author master
* @Date: 2022/3/30 15 13 52
*/
@Configuration
public class RabbitMqConfig {
/**
* 取消订单队列
*/
@Bean
public Queue cancelOrderQueue() {
return new Queue("cancelOrder");
}
/**
* 取消订单交换机
*
* @return
*/
@Bean
CustomExchange cancelOrderExchange() {
HashMap<String, Object> args = new HashMap<>(8);
args.put("x-delayed-type", "direct");
return new CustomExchange("cancelOrder_exchange", "x-delayed-message", true, false, args);
}
/**
* 队列绑定交换机
* @param cancelOrderExchange
* @param cancelOrderQueue
* @return
*/
@Bean
Binding cancelOrderBinding(CustomExchange cancelOrderExchange, Queue cancelOrderQueue) {
return BindingBuilder.bind(cancelOrderQueue)
.to(cancelOrderExchange)
.with("cancelOrder")
.noargs();
}
}
五、发送消息
rabbitTemplate.convertAndSend("cancelOrder_exchange", "cancelOrder", "aaa",
msg -> {
msg.getMessageProperties().setDelay(30 * 1000);
return msg;
});
注:存活时间单位是毫秒,存活时间最多也就是int的最大值
发送成功之后,我们可以看到在交换机的messages delayed已经有了一条消息
六、接收消息
package com.hq.rabbitmq.component;
import com.rabbitmq.client.Channel;
import org.springframework.amqp.rabbit.annotation.RabbitHandler;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.amqp.support.AmqpHeaders;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.messaging.handler.annotation.Header;
import org.springframework.stereotype.Component;
import org.springframework.util.Assert;
import java.io.IOException;
/**
* @Author master
* @Date: 2022/3/30 15 26 46
*/
@Component
@RabbitListener(queues ="cancelOrder")
public class CancelOrderConsumer {
@RabbitHandler
public void handle(String content, Channel channel, @Header(AmqpHeaders.DELIVERY_TAG) long tag) throws IOException {
try {
System.out.println(content);
//确认消费
channel.basicAck(tag,false);
} catch (Exception e){
//消息重发
channel.basicNack(tag,false,false);
throw new RuntimeException(e);
}
}
}