使用RabbitMQ死信队列做延迟任务
引入依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-amqp</artifactId>
<version>2.2.5.RELEASE</version>
</dependency>
配置文件
spring:
rabbitmq:
host: 127.0.0.1 #服务器ip
port: 5672
virtual-host: /
RabbitMQ死信队列的配置类
import org.springframework.amqp.core.*;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class RabbitMQConfiguration {
@Bean
public DirectExchange mymisticDirectExchange() {
return new DirectExchange("mymisticDirectExchange");
}
@Bean
public Queue mymisticQueue() {
return QueueBuilder
//指定队列名称,并持久化
.durable("mymisticQueue")
//设置队列的超时时间为5秒,也就是延迟任务的时间
.ttl(5000)
//指定死信交换机
.deadLetterExchange("mymisticDelayTaskExchange")
.build();
}
@Bean
public Binding sanyouQueueBinding() {
return BindingBuilder.bind(mymisticQueue()).to(mymisticDirectExchange()).with("");
}
@Bean
public DirectExchange mymisticDelayTaskExchange() {
return new DirectExchange("mymisticDelayTaskExchange");
}
@Bean
public Queue mymisticDelayTaskQueue() {
return QueueBuilder
//指定队列名称,并持久化
.durable("mymisticDelayTaskQueue")
.build();
}
@Bean
public Binding mymisticDelayTaskQueueBinding() {
return BindingBuilder.bind(mymisticDelayTaskQueue()).to(mymisticDelayTaskExchange()).with("");
}
}
RabbitMQDelayTaskController用来生产消息,这里没指定延迟时间,是因为在声明队列的时候指定了延迟时间为5s
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.rabbit.connection.CorrelationData;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource;
import java.time.LocalTime;
import java.util.UUID;
@RestController
@Slf4j
public class RabbitMQDelayTaskController {
@Resource
RabbitTemplate rabbitTemplate;
@GetMapping("/rabbitmq/add")
public void addTask(@RequestParam("task") String task){
// 消息ID,需要封装到CorrelationData中
CorrelationData correlationData = new CorrelationData(UUID.randomUUID().toString());
LocalTime localTime = LocalTime.now();
log.info("{} 提交延迟任务消息: {}",localTime , task);
rabbitTemplate.convertAndSend("mymisticDirectExchange" , "" , task ,correlationData);
}
}
RabbitMQDelayTaskConsumer用来监听死信队列,做具体的业务处理
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.rabbit.annotation.RabbitHandler;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Component;
import java.time.LocalTime;
@Slf4j
@Component
@RabbitListener(queues = "mymisticDelayTaskQueue")
public class RabbitMQDelayTaskConsumer {
@RabbitHandler
public void process(String task) {
LocalTime localTime = LocalTime.now();
log.info("{} 监听到死信队列消息: {}", localTime, task);
}
}
测试结果,成功实现5s的延迟任务
http://localhost:8090/rabbitmq/add?task=消息1
实现原理
整个工作流程如下:
消息发送的时候会将消息发送到mymisticDirectExchange这个交换机上
由于mymisticDirectExchange绑定了mymisticQueue,所以消息会被路由到mymisticQueue这个队列上
由于mymisticQueue没有消费者消费消息,并且又设置了5s的过期时间,所以当消息过期之后,消息就被放到绑定的mymisticDelayTaskExchange死信交换机中
消息到达mymisticDelayTaskExchange交换机后,由于跟mymisticDelayTaskQueue进行了绑定,所以消息就被路由到mymisticDelayTaskQueue中,消费者就能从mymisticDelayTaskQueue中拿到消息了