rabbitMq实现延迟队列,从入门到精通的前端进阶学习笔记整理

我们创建两个消费者,分别消费10s和60s的订单

import com.rabbitmq.client.Channel;

import lombok.extern.slf4j.Slf4j;

import org.springframework.amqp.core.Message;

import org.springframework.amqp.rabbit.annotation.RabbitListener;

import org.springframework.stereotype.Component;

import java.io.IOException;

import java.util.Date;

import static com.talent.infocenter.rabbitmq.RabbitMQConfig.DEAD_LETTER_QUEUEA_NAME;

import static com.talent.infocenter.rabbitmq.RabbitMQConfig.DEAD_LETTER_QUEUEB_NAME;

@Slf4j

@Component

public class DeadLetterQueueConsumer {

@RabbitListener(queues = DEAD_LETTER_QUEUEA_NAME)

public void receiveA(Message message, Channel channel) throws IOException {

String msg = new String(message.getBody());

log.info(“当前时间:{},死信队列A收到消息:{}”, new Date().toString(), msg);

channel.basicAck(message.getMessageProperties().getDeliveryTag(), false);

}

@RabbitListener(queues = DEAD_LETTER_QUEUEB_NAME)

public void receiveB(Message message, Channel channel) throws IOException {

String msg = new String(message.getBody());

log.info(“当前时间:{},死信队列B收到消息:{}”, new Date().toString(), msg);

channel.basicAck(message.getMessageProperties().getDeliveryTag(), false);

}

}

  • 创建一个接口进行测试

import com.talent.infocenter.rabbitmq.DelayMessageSender;

import lombok.extern.slf4j.Slf4j;

import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.web.bind.annotation.RequestMapping;

import org.springframework.web.bind.annotation.RequestMethod;

import org.springframework.web.bind.annotation.RequestParam;

import org.springframework.web.bind.annotation.RestController;

import java.util.Date;

import java.util.Objects;

@Slf4j

@RestController

public class RabbitMQMsgController {

@Autowired

private DelayMessageSender sender;

@RequestMapping(value = “sendmsg”, method = RequestMethod.GET)

public void sendMsg(@RequestParam(value = “msg”) String msg, @RequestParam(value = “delayType”) Integer delayType) {

log.info(“当前时间:{},收到请求,msg:{},delayType:{}”, new Date(), msg, delayType);

sender.sendMsg(msg, Objects.requireNonNull(DelayMessageSender.getByIntValue(delayType)));

}

}

接下来开始测试,我用的是swagger,大家可以用postman等其他方法自行测试

在这里插入图片描述

在这里插入图片描述

打开我们的rabbitmq后台就可以看到我们交换机和队列信息

在这里插入图片描述

同样的方法,我们创建一个60s之后才能消费的订单

在这里插入图片描述

在这里插入图片描述

上面的实现仅能设置两个指定的时间10s和60s,接下来我们设置任意时间的延迟队列

4.3 RabbitMq的优化


我们需要一种更通用的方案才能满足需求,那么就只能将TTL设置在消息属性里了,只有如此我们才能更加灵活的实现延迟队列的具体业务开发,方法也很简单,我们只需要增加一个延时队列,用于接收设置为任意延时时长的消息,同时增加一个相应的死信队列和routingkey,但是该方法有个极大的弊端就是如果使用在消息属性上设置TTL的方式,消息可能并不会按时“死亡“,因为RabbitMQ只会检查第一个消息是否过期,如果过期则丢到死信队列,所以如果第一个消息的延时时长很长,而第二个消息的延时时长很短,则第二个消息并不会优先得到执行,此处则不再进行编写代码,但是为了解决这个问题,我们将利用rabbitMq插件实现延迟队列。

4.4 利用插件实现延迟队列


4.4.1 下载插件

点击此处下载

在这里插入图片描述

下载完成之后进行解压,此处推荐bandzip进行解压,并且将解压之后的文件夹放到rabbitmq的安装目录下的plugins目录下

在这里插入图片描述

进入到sbin目录下使用cmd执行以下指令来启用插件

rabbitmq-plugins enable rabbitmq_delayed_message_exchange

在这里插入图片描述

执行以上步骤之后开始重启我们的rabbitmq服务

  • 1.进入到服务

在这里插入图片描述

  • 2.进入到sbin目录,双击rabbitmq-server.bat

在这里插入图片描述

验证是否重启成功访问http://localhost:15672

如果能够访问成功说明重启成功

4.4.2 编写代码

重新创建一个配置类

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.beans.factory.annotation.Qualifier;

import org.springframework.context.annotation.Bean;

import org.springframework.context.annotation.Configuration;

import java.util.HashMap;

import java.util.Map;

@Configuration

public class DelayedRabbitMQConfig {

public static final String DELAYED_QUEUE_NAME = “delay.queue.demo.delay.queue”;

public static final String DELAYED_EXCHANGE_NAME = “delay.queue.demo.delay.exchange”;

public static final String DELAYED_ROUTING_KEY = “delay.queue.demo.delay.routingkey”;

@Bean

public Queue immediateQueue() {

return new Queue(DELAYED_QUEUE_NAME);

}

@Bean

public CustomExchange customExchange() {

Map<String, Object> args = new HashMap<>();

args.put(“x-delayed-type”, “direct”);

return new CustomExchange(DELAYED_EXCHANGE_NAME, “x-delayed-message”, true, false, args);

}

@Bean

public Binding bindingNotify(@Qualifier(“immediateQueue”) Queue queue,

@Qualifier(“customExchange”) CustomExchange customExchange) {

return BindingBuilder.bind(queue).to(customExchange).with(DELAYED_ROUTING_KEY).noargs();

}

}

新建一个消息的发送者

import org.springframework.amqp.rabbit.core.RabbitTemplate;

import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.stereotype.Service;

import static com.talent.infocenter.rabbitMq.DelayedRabbitMQConfig.DELAYED_EXCHANGE_NAME;

import static com.talent.infocenter.rabbitMq.DelayedRabbitMQConfig.DELAYED_ROUTING_KEY;

@Service

public class Provider {

@Autowired

private RabbitTemplate rabbitTemplate;

public void sendDelayMsg(String msg, Integer delayTime) {

rabbitTemplate.convertAndSend(DELAYED_EXCHANGE_NAME, DELAYED_ROUTING_KEY, msg, a -> {

a.getMessageProperties().setDelay(delayTime*1000);

return a;

});

}

}

新建一个消息的消费者

import com.rabbitmq.client.Channel;

import lombok.extern.slf4j.Slf4j;

import org.springframework.amqp.core.Message;

import org.springframework.amqp.rabbit.annotation.RabbitListener;

import org.springframework.stereotype.Component;

import java.io.IOException;

import java.util.Date;

import static com.talent.infocenter.rabbitMq.DelayedRabbitMQConfig.DELAYED_QUEUE_NAME;

@Slf4j

@Component

public class Consumer {

@RabbitListener(queues = DELAYED_QUEUE_NAME)

public void receiveD(Message message, Channel channel) throws IOException {

String msg = new String(message.getBody());

log.info(“当前时间:{},延时队列收到消息:{}”, new Date().toString(), msg);

channel.basicAck(message.getMessageProperties().getDeliveryTag(), false);

}

}

修改我们之前的接口

import com.talent.api.utils.RedisUtils;

import com.talent.infocenter.rabbitMq.Provider;

import lombok.extern.slf4j.Slf4j;

import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.web.bind.annotation.RequestMapping;

import org.springframework.web.bind.annotation.RequestMethod;

import org.springframework.web.bind.annotation.RequestParam;

import org.springframework.web.bind.annotation.RestController;

import java.util.Date;

import java.util.Objects;

@Slf4j

@RestController

public class RabbitMQMsgController {

@Autowired

private Provider provider;

@RequestMapping(value = “sendmsg”, method = RequestMethod.GET)

public void sendMsg(@RequestParam(value = “msg”) String msg, @RequestParam(value = “delayTime”) Integer delayTime) {

log.info(“当前时间:{},收到请求,msg:{},delayTime:{}”, new Date(), msg, delayTime);

provider.sendDelayMsg(msg, delayTime);

}

}

自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数前端工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年Web前端开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
img
img
img
img
img
img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上前端开发知识点,真正体系化!

由于文件比较大,这里只是将部分目录大纲截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且后续会持续更新

如果你觉得这些内容对你有帮助,可以添加V获取:vip1024c (备注前端)
img

算法刷题

大厂面试还是很注重算法题的,尤其是字节跳动,算法是问的比较多的,关于算法,推荐《LeetCode》和《算法的乐趣》,这两本我也有电子版,字节跳动、阿里、美团等大厂面试题(含答案+解析)、学习笔记、Xmind思维导图均可以分享给大家学习。

写在最后

最后,对所以做Java的朋友提几点建议,也是我的个人心得:

  1. 疯狂编程

  2. 学习效果可视化

  3. 写博客

  4. 阅读优秀代码

  5. 心态调整

进阶课程,基本涵盖了95%以上前端开发知识点,真正体系化!**

由于文件比较大,这里只是将部分目录大纲截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且后续会持续更新

如果你觉得这些内容对你有帮助,可以添加V获取:vip1024c (备注前端)
[外链图片转存中…(img-uH6i2Uz8-1711781697376)]

算法刷题

大厂面试还是很注重算法题的,尤其是字节跳动,算法是问的比较多的,关于算法,推荐《LeetCode》和《算法的乐趣》,这两本我也有电子版,字节跳动、阿里、美团等大厂面试题(含答案+解析)、学习笔记、Xmind思维导图均可以分享给大家学习。

写在最后

最后,对所以做Java的朋友提几点建议,也是我的个人心得:

  1. 疯狂编程

  2. 学习效果可视化

  3. 写博客

  4. 阅读优秀代码

  5. 心态调整

  • 26
    点赞
  • 25
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值