0、需求
延迟消息:生产者发送消息时指定一个时间,消费者不会立即收到消息,而是在指定时间之后才收到消息。
延迟任务:设置在一定时间之后才执行的任务。
1、死信交换机
● 当一个队列中的消息满足下列情况之一时,就好成为 死信(dead letter):
- 消费者使用 basic.reject 或 basic.nack 声明消费失败,并且消息的 requeue 参数设置为 false
- 消息是一个过期消息(达到了队列或消息本身设置的过期时间),超时无人消费
- 要投递的队列消息堆积满了,最早的消息可能成为死信
如果队列通过 x-dead-letter-exchange 属性指定了一个交换机,那么该队列中的死信就会投递到这个交换机中,这个交换机成为 死信交换机 (Dead Letter Exchange,简称 DLX)
● 配置类
@Configuration
public class MyRabbitConfig {
@Bean
public FanoutExchange mySimpleFanoutExchange(){
return new FanoutExchange("mySimpleFanoutExchange");
}
@Bean
public Queue mySimpleFanoutQueue(){
// 设置队列的死信交换机
return QueueBuilder.durable("mySimpleFanoutQueue").withArgument("x-dead-letter-exchange", "dlxFanoutExchange").build();
}
@Bean
public Binding mySimpleBinding(){
return BindingBuilder.bind(mySimpleFanoutQueue()).to(mySimpleFanoutExchange());
}
@Bean
public FanoutExchange dlxFanoutExchange(){
return new FanoutExchange("dlxFanoutExchange");
}
@Bean
public Queue dlxFanoutQueue(){
return new Queue("dlxFanoutQueue");
}
@Bean
public Binding myDlxBinding(){
return BindingBuilder.bind(dlxFanoutQueue()).to(dlxFanoutExchange());
}
}
● 发送者
Message msg = MessageBuilder
.withBody("dlx message".getBytes(StandardCharsets.UTF_8))
.setExpiration("10000") // 设置过期时间(ms)
.build();
// 参数:交换机,routingKey, 消息
rabbitTemplate.convertAndSend("mySimpleFanoutExchange", null, msg);
● 消费者
// 只监听死信队列已达到想要的效果
@RabbitListener(queues = "dlxFanoutQueue")
public void dlxFanoutQueueListener(String msg) {
System.out.println("\n死信队列接到了死信交换机的消息:" + msg);
}
2、延迟消息插件
RabbitMQ 官方推出了一个插件,原生支持延迟消息功能。该插件的原理是设计了一种支持延迟消息功能的交换机,当消息投递到交换后可暂存一定时间,到期后再投递到队列。
点击访问 DelayExchange 插件
Linux服务器使用可参考 RabbitMQ 安装延迟队列插件
注:只适用于定时较短的延迟消息,不然会大量损耗服务器性能
2.1、创建延迟队列
// 1、配置类
@Bean
public FanoutExchange delayExchange(){
return (FanoutExchange)ExchangeBuilder.
fanoutExchange("delayExchange")
.delayed() // 设置delay=true
.build();
}
// 2、@RabbitListener
@RabbitListener(bindings = @QueueBinding(
value = @Queue(name = "delayQueue", durable = "true"),
exchange = @Exchange(
name = "delayExchange",
type = ExchangeTypes.FANOUT,
delayed = "true" // 设置delay=true
)
))
public void myDelayListener(String msg) {
// ...
}
2.2、发送延迟消息
rabbitTemplate.convertAndSend("delayExchange", null, "message", new MessagePostProcessor() {
@Override
public Message postProcessMessage(Message message) throws AmqpException {
// 设置延迟消息属性
message.getMessageProperties().setDelay(10000);
return message;
}
});