使用Spring Boot整合Rabbit MQ实现延时队列定时关闭无效订单

一、业务场景

下订单后,30分组内没用付款就要关闭订单等一些需要延时执行的任务。使用定时任务轮询数据库则浪费太多资源

二、环境搭建

1.Rabbit MQ

这里我使用docker安装Rabbit MQ

docker run -d --name rabbitmq -p 5671:5671 -p 5672:5672 -p 4369:4369 -p25672:25672 -p 15671:15671 -p 15672:15672 rabbitmq:management

(PS:Rabbit MQ各个端口的作用)

端口作用
15672管理界面ui使用的端口
15671管理监听端口
5672,5671AMQP 0-9-1 without and with TLSclient端通信口
4369(epmd)epmd代表 Erlang端口映射守护进程,erlang发现口
25672( Erlang distribution) server间内部通信口

2.Spring Boot整合Rabbit MQ

引入依赖

  <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-amqp</artifactId>
        </dependency>
rabbitmq:
    addresses: localhost
    port: 5672
    virtual-host: /
    #手动ack消息确认模式
    listener:
      simple:
        acknowledge-mode: manual

三、实现业务

RabbitMQ队列本身是没有直接实现支持延迟队列的功能,但可以通过它的Time-To-Live Extensions(消息存活时间) 与 Dead Letter Exchange 的特性模拟出延迟队列的功能。
普通队列设置相关属性后就成为了死信队列
因此,我们需要1个交换机,一个死信队列和一个普通队列和两个路由Key实现延时队列功能

在这里插入图片描述

1.创建需要的交换机,队列,bind

RabbitMQ支持java客户端的操作,我们只需把交换机,队列,bind放到spring容器中,RabbitMQ就为自动为我们创建(不会覆盖原有的)

@Bean
    public Queue orderDelayQueue()
    {
        //死信队列的属性
        Map<String,Object> arguments = new HashMap<>();
        //指定order-event-exchange为死信交换机,消息过期后将会投到死信交换机
        arguments.put("x-dead-letter-exchange","order-event-exchange");
        //指定死信的路由key
        arguments.put("x-dead-letter-routing-key","order.release.order");
        //ttl time to live 消息存活时间,为了测试,设置为1分钟
        arguments.put("x-message-ttl",60000);
        //队列名,是否持久,是否排他,是否自动删除
        return new Queue("order.delay.queue",true,false,false,arguments);

    }

    @Bean
    public Queue orderReleaseOrderQueue()
    {
        return new Queue("order.release.queue",true,false,false);

    }

    @Bean
    public Exchange orderEventExchange()
    {
        return new TopicExchange("order-event-exchange",true,false);

    }

    @Bean
    public Binding orderCreateOrderBingding()
    {

        return new Binding("order.delay.queue",
                Binding.DestinationType.QUEUE,
                "order-event-exchange",
                "order.create.order",null);
    }

    @Bean
    public Binding orderReleaseBingding()
    {
        return new Binding("order.release.queue",
                Binding.DestinationType.QUEUE,
                "order-event-exchange",
                "order.release.order",null);

    }

可以到ui界面看我们刚刚创建的这些玩意
在这里插入图片描述
在这里插入图片描述

2.业务代码

a) 订单创建后,放入死信队列
 rabbitTemplate.convertAndSend("order-event-exchange", "order.create.order", order);
b)监听消息释放队列,判断是否需要关单

因为使用的手动消息确认机制,需要在代码中确认接收消息还是退回消息

@Service
@RabbitListener(queues = "order.release.queue")
public class OrderCloseListener {
    @Autowired
    OrderService orderService;

    //关闭订单
    @RabbitHandler
    public void closeOrder(OrderEntity orderEntity, Channel channel, Message message) throws IOException {
        try {
            //只有未付款的订单要关闭
           OrderEntity oreder = orderService.getById(orderEntity.getId());
            if(oreder.getStatus() == OrderStatusEnum.CREATE_NEW.getCode()) {
                orderService.closeOrder(orderEntity.getId());
                System.out.println("接收到的死信,即为交易的订单:"+orderEntity);
            }
            //手动确认接收消息
            channel.basicAck(message.getMessageProperties().getDeliveryTag(),false);
        }
        catch (Exception e)
        {
            //关单失败,退回消息给队列
            channel.basicReject(message.getMessageProperties().getDeliveryTag(),true);

        }

    }


}

四、测试

新建一个订单
在这里插入图片描述
死信队列收到了发来的消息
在这里插入图片描述

1分钟后,消息死亡,来到普通队列。监听队列的Listenser执行光单操作

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值