• springboot使用RabbitMQ实现延时任务


    延时队列顾名思义,即放置在该队列里面的消息是不需要立即消费的,而是等待一段时间之后取出消费。
    那么,为什么需要延迟消费呢?我们来看以下的场景

    订单业务: 在电商/点餐中,都有下单后 30 分钟内没有付款,就自动取消订单。
    短信通知: 下单成功后 60s 之后给用户发送短信通知。
    失败重试: 业务操作失败后,间隔一定的时间进行失败重试。

    本文基于springboot,使用rabbitmq_delayed_message_exchange插件实现延时队列(RabbitMQ及其插件环境安装点此),具体实践如下:

    application.properties

    spring.rabbitmq.username=root
    spring.rabbitmq.password=root
    spring.rabbitmq.host=192.168.1.123
    spring.rabbitmq.port=5672
    spring.rabbitmq.virtual-host=test

    XdelayConfig.java

    import org.springframework.amqp.core.Binding;
    import org.springframework.amqp.core.BindingBuilder;
    import org.springframework.amqp.core.CustomExchange;
    import org.springframework.amqp.core.Queue;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    
    import java.util.HashMap;
    import java.util.Map;
    
    @Configuration
    public class XdelayConfig {
     
        /**
         * 立即消费的队列名称
         */
        public static final String IMMEDIATE_QUEUE_XDELAY = "queue.xdelay.immediate";
        /**
         * 延时的exchange
         */
        public static final String DELAYED_EXCHANGE_XDELAY = "exchange.xdelay.delayed";
        public static final String DELAY_ROUTING_KEY_XDELAY = "routingkey.xdelay.delay";
    
        /**
         * 创建一个立即消费队列
         *
         * @return
         */
        @Bean
        public Queue immediateQueue() {
            // 第一个参数是创建的queue的名字,第二个参数是是否支持持久化
            return new Queue(IMMEDIATE_QUEUE_XDELAY, true);
        }
    
        @Bean
        public CustomExchange delayExchange() {
            Map<String, Object> args = new HashMap<String, Object>();
            args.put("x-delayed-type", "direct");
            return new CustomExchange(DELAYED_EXCHANGE_XDELAY, "x-delayed-message", true, false, args);
        }
    
        /**
         * 把立即消费的队列和延时消费的exchange绑定在一起
         *
         * @return
         */
        @Bean
        public Binding bindingNotify() {
            return BindingBuilder.bind(immediateQueue()).to(delayExchange()).with(DELAY_ROUTING_KEY_XDELAY).noargs();
        }
    }

    XdelaySender.java 生产者

    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    import org.springframework.amqp.rabbit.core.RabbitTemplate;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Component;
    
    import java.text.SimpleDateFormat;
    import java.util.Date;
    
    /**
     * 生产者
     */
    @Component
    public class XdelaySender {
        private final static Logger logger = LoggerFactory.getLogger(XdelaySender.class);
        @Autowired
        private RabbitTemplate rabbitTemplate;
    
        public void send(String msg, int delayTime) {
            logger.info("msg= " + msg + ".delayTime" + delayTime);
            SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
            this.rabbitTemplate.convertAndSend(XdelayConfig.DELAYED_EXCHANGE_XDELAY, XdelayConfig.DELAY_ROUTING_KEY_XDELAY, msg, message -> {
                message.getMessageProperties().setDelay(delayTime);
                System.out.println(sdf.format(new Date()) + " Delay sent.");
                return message;
            });
        }
    }

    XdelayReceiver.java 消费者

    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    import org.springframework.amqp.rabbit.annotation.EnableRabbit;
    import org.springframework.amqp.rabbit.annotation.RabbitListener;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.stereotype.Component;
    
    import java.text.SimpleDateFormat;
    import java.util.Date;
    
    /**
     * 消费者
     */
    @Component
    @EnableRabbit
    @Configuration
    public class XdelayReceiver {
        private final static Logger logger = LoggerFactory.getLogger(XdelayReceiver.class);
    
        @RabbitListener(queues = com.example.antchat.rabbitmq.XdelayConfig.IMMEDIATE_QUEUE_XDELAY)
        public void get(String msg) {
            SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
            logger.info("收到延时消息时间:" + sdf.format(new Date()) + " Delay sent.");
            logger.info("收到延时消息:" + msg);
        }
    }

    测试

    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RestController;
    
    @RestController
    public class RabbitMQController {
        @Autowired
        XdelaySender xdelaySender;
        @RequestMapping("/testRabbit")
        public void testRabbit() {
            xdelaySender.send("我来发一个测试消息,10秒", 10000);//10秒
            xdelaySender.send("我来发一个测试消息,2秒", 2000);//2秒
            xdelaySender.send("我来发一个测试消息,1秒", 2000);//1秒
        }
    }

    参考博文:

    微服务-springboot-rabbitmq:实现延时队列

  • 相关阅读:
    C#3.0实现变异赋值(Mutantic Assignment)
    博客园积分算法探讨
    C#动静结合编程之二: 两种哲学
    REST构架风格介绍之二:CRUD
    C# vs C++之一:委托 vs 函数指针
    REST构架风格介绍之一:状态表述转移
    C#动静结合编程之三:Duck Typing
    C#动静结合编程之四:泛型委托
    C# vs C++之二:GC vs RAII
    Ecshop文章分类列表页如何自定义Title以提高SEO效果
  • 原文地址:https://www.cnblogs.com/wintercloud/p/10877399.html
Copyright © 2020-2023  润新知