RabbitMq DLX 实现延迟队列
我们可以把死信队列就当成延迟队列。
具体来说是这样:
假如一条消息需要延迟 30 分钟执行,我们就设置这条消息的有效期为 30 分钟,同时为这条消息配置死信交换机和死信 routing_key
,并且不为这个消息队列设置消费者,那么 30 分钟后,这条消息由于没有被消费者消费而进入死信队列,此时我们有一个消费者就在“蹲点”这个死信队列,消息一进入死信队列,就立马被消费了。
配置:mqConfig
package com.pay.fyServe.config; 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.boot.SpringBootConfiguration; import org.springframework.context.annotation.Bean; import java.util.HashMap; import java.util.Map; import static com.pay.fyServe.constants.FyConstant.*; @SpringBootConfiguration public class FyServeMqConfig { //region /** * 声明正常队列 * * @return */ @Bean public Queue fyServeRefreshQueue() { //只需要在声明业务队列时添加x-dead-letter-exchange,值为死信交换机 Map<String, Object> map = new HashMap<>(1); map.put("x-dead-letter-exchange", FY_SERVE_REFRESH_DLK_EXCHANGE); //该参数x-dead-letter-routing-key可以修改该死信的路由key,不设置则使用原消息的路由key map.put("x-dead-letter-routing-key", FY_SERVE_REFRESH_DLK_ROUTE_KEY); return new Queue(FY_SERVE_REFRESH_QUEUE, true, false, false, map); } //声明交换机 @Bean public DirectExchange fyServeRefreshExchange() { return new DirectExchange(FY_SERVE_REFRESH_EXCHANGE, true, false); } //声明死信交换机 @Bean public DirectExchange fyServeRefreshDlkExchange() { return new DirectExchange(FY_SERVE_REFRESH_DLK_EXCHANGE, true, false); } //声明死信队列 @Bean public Queue fyServeRefreshDlkQueue() { return new Queue(FY_SERVE_REFRESH_DLK_QUEUE, true, false, false); } //正常交换机-->正常队列 @Bean public Binding fyServeRefreshBind() { return BindingBuilder.bind(this.fyServeRefreshQueue()).to(fyServeRefreshExchange()).with(FY_SERVE_REFRESH_ROUTE_KEY); } //死信交换机-->死信队列 // (正常队列 超时后 ——> 死信交换机->死信队列 )--> // 因此,向正常交换机发消息,监听死信队列,就可以实现消息延时消费 @Bean public Binding fyServeRefreshDlkBind() { return BindingBuilder.bind(fyServeRefreshDlkQueue()).to(fyServeRefreshDlkExchange()).with(FY_SERVE_REFRESH_DLK_ROUTE_KEY); } //endregion }
封装方法:RabbitUtil
public class RabbitUtil { @Autowired private RabbitTemplate rabbitTemplate; public <T> void send(String exchange, String routeKey, T data, int delay) { rabbitTemplate.convertAndSend(exchange, routeKey, data, message -> { //设置消息的过期时间,是以毫秒为单位的 message.getMessageProperties().setExpiration(String.valueOf(delay * 1000)); return message; }); } public <T> void send(String topic, T data) { rabbitTemplate.convertAndSend(topic, data); } }
调用:
@Autowired private RabbitUtil rabbitUtil; rabbitUtil.send(FyConstant.FY_SERVE_REFRESH_EXCHANGE, FyConstant.FY_SERVE_REFRESH_ROUTE_KEY, orderInfo.getId(), 5);
异步监听:
@Slf4j @Component public class FyServeRefreshListener { @RabbitHandler @RabbitListener(queues = FyConstant.FY_SERVE_REFRESH_DLK_QUEUE, containerFactory = "containerFactory") // 队列指向死信队列 public void process(Long orderId) { log.info("开始查询订单"); .......其他数据处理 } }