一. 延迟队列的应用场景
1.具体应用
关于消息队列我们已经很熟悉了,我们知道在消息队列中可以实现延迟队列效果,那你知道延迟队列有哪些使用场景吗?这里我给大家总结了延迟队列的几个经典使用场景,看看你的项目中是否涉及到了。
淘宝七天自动确认收货。在我们签收商品后,物流系统会在七天后延时发送一个消息给支付系统,通知支付系统将货款打给商家,这个过程持续七天,就是使用了消息中间件的延迟推送功能;
订单在十分钟之内未支付则自动取消;
新创建的店铺,如果在十天内都没有上传过商品,则自动发送消息提醒;
用户注册成功后,如果三天内没有登陆则进行短信提醒;
用户发起退款,如果三天内没有得到处理则通知相关运营人员;
预定会议后,需要在预定的时间点前十分钟通知各个与会人员参加会议。
2.延迟队列简介
-
RabbitMQ 3.6.x 之前,我们一般采用死信队列+TTL过期时间来实现延迟队列,通过TTL+死信队列完成。
-
从RabbitMQ 3.6.x 开始,RabbitMQ 官方直接提供了延迟队列插件,可以下载放置到 RabbitMQ 根目录下的 plugins 下,这样就可以很轻松的实现延迟队列效果了。
那么延迟队列到底该怎么使用呢?今天我就通过一个小案例来带大家实现一下。
二. 本次需求
以下是我们今天要实现的基本需求。
-
用户注册成功后,如果三天内没有登陆则进行短信提醒。
你现在有没有什么实现思路呢?别急,请跟着我一点点往下看吧。
三. 安装配置RabbitMQ
我们采用Docker来安装配置RabbitMQ及其插件,如果你对Docker还不了解,可以参考如下视频教程:
Docker快速入门教程
1.Docker 安装 RabbitMQ
1.1 查找RabbitMQ镜像
docker search rabbitmq
1.2 拉取RabbitMQ镜像
docker pull rabbitmq (镜像未配有控制台)
docker pull rabbitmq:management (镜像配有控制台)
注意:
-
rabbitmq是官方镜像,该镜像不带控制台。如果要安装带控制台的镜像,需要在拉取镜像时附带;
-
tag标签,例如:management;
-
tag标签可以通过https://hub.docker.com//rabbitmq?tab=tags来查询。
1.3 启动RabbitMQ
docker run -d --name rabbitmq -e RABBITMQ_DEFAULT_USER=admin -e RABBITMQ_DEFAULT_PASS=admin -p 15672:15672 -p 5672:5672 rabbitmq:management
创建容器并运行(15672是管理界面的端口,5672是服务的端口;
这里顺便将管理系统的用户名和密码设置为admin admin;
-e RABBITMQ_DEFAULT_USER=admin -e RABBITMQ_DEFAU LT_PASS=admin.
1.4 停止RabbitMQ
docker stop rabbitmq
1.5 重启 RabbitMQ 容器
docker restart rabbitmq
1.6 查看 RabbitMQ 容器进程信息
docker top rabbitmq
2.安装延迟队列插件
2.1 下载与RabbitMQ相匹配的插件版本
https://github.com/rabbitmq/rabbitmq-delayed-message-exchange/
https://github.com/rabbitmq/rabbitmq-delayed-message-exchange/ releases/tag/v3.8.0
2.2 上传插件到服务器的/root文件夹下,然后进行如下操作
#拷贝到rabbitmq容器 773067241f96 中
docker cp rabbitmq_delayed_message_exchange-3.8.9-0199d11c.ez rabbitmq:/plugins
#进入容器
docker exec -it rabbitmq /bin/bash
#启用插件
rabbitmq-plugins enable rabbitmq_delayed_message_exchange
#查看
rabbitmq-plugins list
#重新启动容器
docker restart rabbitmq
四. 实现延迟消息
1.基本需求
用户注册成功后,如果三天内没有登陆则进行短信提醒。本需求基本架构如下图所示:
2.生产者Provider
Provider部分代码如下所示:
**
* @ClassName UserController
* @Description TODO 用户管理业务模块
* @Author 千锋-南京-Wilson
* @Version 1.0
*/
@Controller
@RequestMapping("user")
@Slf4j
public class UserController {
/**消息队列*/
@Autowired
private AmqpTemplate amqpTemplate;
/**
* 注册功能
* @return
*/
@ResponseBody
@GetMapping("register")
public String register(@RequestParam("uname") String uname){
// 延迟的时间毫秒 ms
int delayTime=8000;
log.info("用户业务逻辑注册成功--》"+uname+"\t"+new Date().toString()+"\t"+delayTime+"毫秒");
//队列发送 邮件 延迟 delayTime
amqpTemplate.convertAndSend("delayed.exchange.user.register",
"delayed.key.user.register",uname,msg->{
msg.getMessageProperties().setDelay(delayTime);
return msg;
});
return "用户注册成功";
}
3.交换机配置
交换机代码如下所示:
package com.qfjy.config.example5;
**
* @ClassName UserDelayedQueueConfig
* @Description TODO 用户延迟队列配置
* @Author 千锋-南京-Wilson
* @Version 1.0
*/
@Configuration
public class UserDelayedQueueConfig {
/**
* TODO 1、定义交换机 delayed.exchange.user.register
* 2、定义队列 delayed.queue.user.register
* 3、路由KEY delayed.key.user.register
* 4、队列绑定交换机路由
*/
/**
* TODO 定义交换机
*/
@Bean
public CustomExchange delayedExchangeUserRegister(){
/**
* String name, 交换机名称
* String type, 交换机消息类型(x-delayed-message)
* boolean durable, 是否持久化
* boolean autoDelete,是否删除
* Map<String, Object> arguments // 队列中的消息什么时候会自动被删除?
* arguments.put("x-message-ttl",10000); //设置过期时间
* arguments.put("x-expires", 10000); //x-expires用于当多长时间没有消费者访问该队列的时候,该队列会自动删除,
* arguments.put("x-max-length", 4); //x-max-length:用于指定队列的长度,如果不指定,可以认为是无限长,例如指定队列的长度是4,当超过4条消息,前面的消息将被删除,给后面的消息腾位
*/
Map<String, Object> arguments=new HashMap<>();
arguments.put("x-delayed-type","direct");
return new CustomExchange("delayed.exchange.user.register","x-delayed-message",
true,false,arguments);
}
/**
* TODO 定义队列 delayed.queue.user.register
*/
@Bean
public Queue delayedQueueUserRegister(){
return new Queue("delayed.queue.user.register");
}
/**
* TODO 3 绑定 交换机 队列 路由KEY
* @return
*/
@Bean
public Binding bindDelayedQueueDelayedExchangeUserRegister(
Queue delayedQueueUserRegister,
CustomExchange delayedExchangeUserRegister){
return BindingBuilder.bind(delayedQueueUserRegister).to(delayedExchangeUserRegister).with("delayed.key.user.register").noargs();
}
}
4.消费者Consumer
消费者部分的代码如下所示:
@Service
@Slf4j
public class UserRegisterServiceImpl {
/**
* 用户 邮件发送
*/
@RabbitListener(queues = {"delayed.queue.user.register"})
public void sendEmail(String uname){
log.info("用户发送邮件成功--》"+uname+"\t"+new Date().toString());
}
}
这样我们通过以上配置和代码,就可以实现这个基本需求了。
如果你想更好地学习并掌握Java相关的更多知识和用法,大家可以扫码获取相关资源哦。