目录
方法一:通过插件实现
优点
不阻塞的延迟队列
实现
1、安装rabbitMQ延迟插件 ---> rabbitmq-delayed-message-exchange (高版本的rabbitMQ安装完插件之后无需重启)当出现添加交换机有如图所示的选项时,说明安装插件成功
2、定义常量
/**
* 访客延迟队列
*/
String VISITOR_DELAY_QUEUE ="yxb.visitor.delay.queue";
/**
* 访客延迟交换机
*/
String VISITOR_DELAY_EXCHANGE = "yxb.visitor.delay.exchange";
/**
* 访客延迟消息路由key
*/
String VISITOR_DELAY_ROUTE_KEY = "yxb.receive.visitor.delay.routeKey";
3、创建延迟队列
/**
* 访客延迟队列
* @return
*/
@Bean
Queue visitorDelayQueue() {
return new Queue(VISITOR_DELAY_QUEUE);
}
4、创建延迟交换机
@Bean
public CustomExchange visitorDelayExchange(){
HashMap<String, Object> args = new HashMap<>();
args.put("x-delayed-type","direct");
return new CustomExchange(VISITOR_DELAY_EXCHANGE,"x-delayed-message",true,false,args);
}
5、绑定延迟队列和交换机
/**
* 延迟队列绑定交换机
* @param visitorDelayQueue 延迟队列
* @param visitorDelayExchange 交换机
* @return Binding
*/
@Bean
public Binding bindVisitorDelayExchange(@Qualifier("visitorDelayQueue") Queue visitorDelayQueue,
@Qualifier("visitorDelayExchange") CustomExchange visitorDelayExchange){
return BindingBuilder.bind(visitorDelayQueue).to(visitorDelayExchange).with(VISITOR_DELAY_ROUTE_KEY).noargs();
}
6、发送延迟消息
rabbitTemplate.convertAndSend(mqMessage.getExchange(),mqMessage.getRoutingKey(),mqMessage, message -> {
// 设置延迟毫秒值
message.getMessageProperties().setDelay(delayTimes.intValue());
return message;
}, new CorrelationData(mqMessage.getId()));
7、监听延迟队列
@Component
@AllArgsConstructor
@Slf4j
public class VisitorEventDrive {
private final VisitorOrdersService visitorOrdersService;
@RabbitHandler
@RabbitListener(queues = MqConstant.VISITOR_DELAY_QUEUE)
public void receiveEvent(Message message, Channel channel, MqMessage mqMessage){
try {
//doSomething
} catch (Exception e) {
e.toString();
}
}
}
方法二:通过死信实现延迟队列
缺点
会存在阻塞的情况
实现
先向队列中发送一个60秒到期的消息,再往队列中发送一个30秒到期的消息.预想的是队列先执行30秒的消息,再执行60秒的消息.但是实际情况是60秒的消息会阻塞队列,导致先执行了60秒的消息,再执行30秒的消息.(延迟30秒的要求没有实现)
1、创建死信队列和转发队列
/**
* 访客二维码死信队列
* @return
*/
@Bean
Queue visitorTtlQueue() {
return QueueBuilder
.durable(MqConstant.VISITOR_TTL_QUEUE)
// 配置到期后转发的交换
.withArgument("x-dead-letter-exchange", MqConstant.VISITOR_DIRECT_EXCHANGE)
// 配置到期后转发的路由键
.withArgument("x-dead-letter-routing-key", MqConstant.TTL_CHANGE_ROUTE_KEY)
.build();
}
/**
* 访客二维码死信消息转发队列
* @return 队列
*/
@Bean
public Queue visitorTtlChangeQueue(){
return new Queue(VISITOR_TTL_CHANGE_QUEUE);
}
2、创建直连交换机和延时交换机
/**
* 访客直连交换机
* @return 交换机
*/
@Bean
public DirectExchange visitorDirectExchange(){
return new DirectExchange(VISITOR_DIRECT_EXCHANGE);
}
/**
* 延时消息交换机配置
* @return DirectExchange
*/
@Bean
DirectExchange messageTtlDirect() {
return (DirectExchange) ExchangeBuilder.directExchange(MESSAGE_TTL_EXCHANGE).durable(true).build();
}
3、绑定队列和交换机
/**
* 死信队列绑定交换机
* @param visitorTtlQueue 死信队列
* @param messageTtlDirect 交换机
* @return Binding
*/
@Bean
public Binding bindVisitorTtlDirectExchange(@Qualifier("visitorTtlQueue") Queue visitorTtlQueue,
@Qualifier("messageTtlDirect") DirectExchange messageTtlDirect){
return BindingBuilder.bind(visitorTtlQueue).to(messageTtlDirect).with(TTL_ROUTE_KEY);
}
/**
* 转发队列绑定交换机
* @param visitorTtlChangeQueue
* @param visitorDirectExchange
* @return Binding
*/
@Bean
public Binding bindVisitorTtlChangeExchange(@Qualifier("visitorTtlChangeQueue") Queue visitorTtlChangeQueue,
@Qualifier("visitorDirectExchange") DirectExchange visitorDirectExchange){
return BindingBuilder.bind(visitorTtlChangeQueue).to(visitorDirectExchange).with(MqConstant.TTL_CHANGE_ROUTE_KEY);
}
4、发送死信消息
rabbitTemplate.convertAndSend(mqMessage.getExchange(),mqMessage.getRoutingKey(),mqMessage, message -> {
// 设置延迟毫秒值
message.getMessageProperties().setExpiration(String.valueOf(delayTimes));
return message;
}, new CorrelationData(mqMessage.getId()));
5、监听转发队列
@Component
@AllArgsConstructor
@Slf4j
public class VisitorEventDrive {
@RabbitHandler
@RabbitListener(queues = MqConstant.VISITOR_TTL_CHANGE_QUEUE)
public void receiveEvent(Message message, Channel channel, MqMessage mqMessage){
try {
//doSomeThing
}catch (Exception e) {
}
}
}