RabbitMQ延迟消息学习
准备做一个禁言自动解除的功能,立马想到了订单的超时自动解除,刚好最近在看RabbitMQ的实现,于是想用它实现,查询了相关文档发现确实可以实现,动手编写了这篇短文。
准备工作
1、Erlang安装请参考windows下安装Erlang
2、mq安装晴参考RabbitMQ安装
3、延迟消息插件安装rabbitmq_delayed_message_exchange
#插件下载地址(选择与mq版本匹配的插件版本)
http://www.rabbitmq.com/community-plugins.html
#安装命令如下(在安装目录sbin下执行如下命令)
rabbitmq-plugins enable rabbitmq_delayed_message_exchange
创建项目
我选择的是在springboot中集成RabbitMQ,配置相对简单很多。


项目创建好后,在application.properties中加入RabbitMQ参数:
#RabbitMQ config
spring.rabbitmq.host=127.0.0.1
spring.rabbitmq.port=5672
spring.rabbitmq.username=guest
spring.rabbitmq.password=guest
#Custom config
rabbitmq.exchange=test_exchange
rabbitmq.queue=test_queue_1
定义ConnectionFactory和RabbitTemplate
package com.xsh.mq.config;
import org.springframework.amqp.rabbit.connection.CachingConnectionFactory;
import org.springframework.amqp.rabbit.connection.ConnectionFactory;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
@ConfigurationProperties(prefix = "spring.rabbitmq")
public class RabbitMqConfig {
private String host;
private int port;
private String userName;
private String password;
@Bean
public ConnectionFactory connectionFactory() {
CachingConnectionFactory cachingConnectionFactory = new CachingConnectionFactory(host,port);
cachingConnectionFactory.setUsername(userName);
cachingConnectionFactory.setPassword(password);
cachingConnectionFactory.setVirtualHost("/");
cachingConnectionFactory.setPublisherConfirms(true);
return cachingConnectionFactory;
}
@Bean
public RabbitTemplate rabbitTemplate() {
RabbitTemplate rabbitTemplate = new RabbitTemplate(connectionFactory());
return rabbitTemplate;
}
public String getHost() {
return host;
}
public void setHost(String host) {
this.host = host;
}
public int getPort() {
return port;
}
public void setPort(int port) {
this.port = port;
}
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
}
Exchange和Queue配置
package com.xsh.mq.config;
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.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.util.HashMap;
import java.util.Map;
/**
* 配置队列
*/
@Configuration
public class QueueConfig {
@Value("${rabbitmq.exchange}")
private String exchangeName;
@Value("${rabbitmq.queue}")
private String queueName;
@Bean
public CustomExchange delayExchange() {
Map<String, Object> args = new HashMap<>();
args.put("x-delayed-type", "direct");
//使用的是CustomExchange,不是DirectExchange,另外CustomExchange的类型必须是x-delayed-message
return new CustomExchange(exchangeName, "x-delayed-message",true, false,args);
}
@Bean
public Queue queue() {
Queue queue = new Queue(queueName, true);
return queue;
}
@Bean
public Binding binding() {
return BindingBuilder.bind(queue()).to(delayExchange()).with(queueName).noargs();
}
}
消息发送
package com.xsh.mq.service;
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.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
@Service
public class MessageServiceImpl {
/**
* 日志
*/
private static final Logger logger = LoggerFactory.getLogger(MessageServiceImpl.class);
/**
* rabbitMQ模板
*/
@Autowired
private RabbitTemplate rabbitTemplate;
@Value("${rabbitmq.exchange}")
private String exchangeName;
/**
* 发送消息
* @param queueName 队列名称
* @param msg 消息内容
* @param delay 延迟时长 默认3秒
*/
public void sendMsg(String queueName,String msg,Integer delay) {
if(null == delay){
delay = 3000;
}
logger.info("》》》》发送消息");
Integer finalDelay = delay;
rabbitTemplate.convertAndSend(exchangeName, queueName, msg, message -> {
//必须添加header x-delay
message.getMessageProperties().setHeader("x-delay", finalDelay);
return message;
});
}
}
这里发送消息我定义了一个延迟参数,传入的延迟是多少,消息就延迟多少,方便消息延迟不一样
消费消息
package com.xsh.mq.service;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Component;
@Component
public class MessageReceiver {
/**
* 日志
*/
private static final Logger logger = LoggerFactory.getLogger(MessageReceiver.class);
@RabbitListener(queues = "${rabbitmq.queue}")
public void receive(String msg) {
logger.info("收到消息:{}", msg);
}
}
测试发送接收
先运行springboot项目,然后编写单元测试用例
package com.xsh.mq;
import com.xsh.mq.service.MessageServiceImpl;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
@RunWith(SpringRunner.class)
@SpringBootTest
public class MqApplicationTests {
@Test
public void contextLoads() {
}
@Autowired
private MessageServiceImpl messageService;
@Value("${rabbitmq.queue}")
private String queueName;
@Test
public void send() {
messageService.sendMsg(queueName, "delayMsg2", 1000 * 60 * 2);
messageService.sendMsg(queueName, "delayMsg1", 1000 * 60);
messageService.sendMsg(queueName, "delayMsg3", 1000 * 60*3);
}
}
这里我发送了三条延迟消息,控制台结果如图:

消费者接收到的消息为:

从执行结果来看,demo基本实现,RabbitMQ其他细节还有待继续看。
参考文章:Scheduling Messages with RabbitMQ
RabbitMQ延迟消息学习的更多相关文章
- Spring Boot RabbitMQ 延迟消息实现完整版
概述 曾经去网易面试的时候,面试官问了我一个问题,说 下完订单后,如果用户未支付,需要取消订单,可以怎么做 我当时的回答是,用定时任务扫描DB表即可.面试官不是很满意,提出: 用定时任务无法做到准实时 ...
- RabbitMQ延迟消息的延迟极限是多少?
之前在写Spring Cloud Stream专题内容的时候,特地介绍了一下如何使用RabbitMQ的延迟消息来实现定时任务.最近正好因为开发碰到了使用过程中发现,延迟消息没有效果,消息直接就被消费了 ...
- RabbitMQ延迟消息:死信队列 | 延迟插件 | 二合一用法+踩坑手记+最佳使用心得
前言 前段时间写过一篇: # RabbitMQ:消息丢失 | 消息重复 | 消息积压的原因+解决方案+网上学不到的使用心得 很多人加了我好友,说很喜欢这篇文章,也问了我一些问题. 因为最近工作比较忙, ...
- RabbitMQ延迟消息队列实现定时任务完整代码示例
- Spring Cloud Stream 使用延迟消息实现定时任务(RabbitMQ)
应用场景 通常在应用开发中我们会碰到定时任务的需求,比如未付款订单,超过一定时间后,系统自动取消订单并释放占有物品. 许多同学的第一反应就是通过spring的schedule定时任务轮询数据库来实现, ...
- 15-EasyNetQ之对延迟消息插件的支持
RabbitMQ延迟消息插件仍然在实验阶段.你使用这个功能要自担风险. RabbitMQ延迟消息插件为RabbitMQ增加了新的交换机类型,允许延时消息投递. EasyNetQ为交换机通过定义一种新的 ...
- EasyNetQ使用(八)【对延迟消息插件的支持,自动订阅者】
RabbitMQ延迟消息插件仍然在实验阶段.你使用这个功能要自担风险. RabbitMQ延迟消息插件为RabbitMQ增加了新的交换机类型,允许延时消息投递. EasyNetQ为交换机通过定义一种新的 ...
- rabbitmq学习(二):rabbitmq(消息队列)的作用以及rabbitmq之直连交换机
前言 上篇介绍了AMQP的基本概念,组成及其与rabbitmq的关系.了解了这些东西后,下面我们开始学习rabbitmq(消息队列)的作用以及用java代码和rabbitmq通讯进行消息发布和接收.因 ...
- rabbitmq的延迟消息队列实现
第一部分:延迟消息的实现原理和知识点 使用RabbitMQ来实现延迟任务必须先了解RabbitMQ的两个概念:消息的TTL和死信Exchange,通过这两者的组合来实现上述需求. 消息的TTL(Tim ...
随机推荐
- 机器学习(Machine Learning)算法总结-决策树
一.机器学习基本概念总结 分类(classification):目标标记为类别型的数据(离散型数据)回归(regression):目标标记为连续型数据 有监督学习(supervised learnin ...
- Python函数——装饰器
前言 给下面的函数加上运行时间 def fib(n): a, b = 0, 1 for i in range(n): print(b) a, b = b, a+b return b a = fib(5 ...
- 脚手架vue-cli系列五:基于Nightwatch的端到端测试环境
不同公司和组织之间的测试效率迥异.在这个富交互和响应式处理随处可见的时代,很多组织都使用敏捷的方式来开发应用,因此测试自动化也成为软件项目的必备部分.测试自动化意味着使用软件工具来反复运行项目中的测试 ...
- 脚手架vue-cli系列二:vue-cli的工程模板与构建工具
上篇文章我们提到了vue-cli的工程模板.这里我们来详细的进行介绍. vue-cli提供的脚手架只是一个最基础的,也可以说是Vue团队认为的工程结构的一种最佳实践.对于初学者或者以前曾从事Angul ...
- sql server 备份与恢复系列六 文件组备份与还原
一. 概述 文件备份是指备份一个或多个文件或文件组中的所有数据.使用文件备份能够只还原损坏的文件,而不用还原数据库的其余部份,从而加快恢复速度.例如,如果数据库由位于不同磁盘上的若干文件组成,在其中一 ...
- Java工程师学习指南 完结篇
Java工程师学习指南 完结篇 先声明一点,文章里面不会详细到每一步怎么操作,只会提供大致的思路和方向,给大家以启发,如果真的要一步一步指导操作的话,那至少需要一本书的厚度啦. 因为笔者还只是一名在校 ...
- iOS ipa包瘦身,iOS8及以下text段超60MB
前沿 很早之前写过一篇相关文章,不过博客主机上跑路了之后数据没了,凭着记忆补了下相关资料 ipa安装包瘦身 清理无用图片,图片压缩(PNG换WebP和JPG),处于某种不可抗拒的原因,导致有部分3X图 ...
- ARP的通信过程
在当今的以太网络通信中,在IP数据包中有两个必不可少的地址,那就是IP地址和网卡地址(即MAC地址),在数据包中,无论是IP地址还是MAC地址,都有源地址和目标地址,因为通信是双方的,所以就必须同时拥 ...
- Scala字符串与容器
String 前文已经说明了字符串的声明方式: var s = "Hello World"; var s: String = "Hello World"; 在 ...
- 【转】 Apk文件及其编译过程
Apk文件概述 Android系统中的应用程序安装包都是以apk为后缀名,其实apk是Android Package的缩写,即android安装包. 注:apk包文件其实就是标准的zip文件,可以直接 ...