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 ...
随机推荐
- JAVA发送http get/post请求,调用http接口、方法
import java.io.BufferedReader; import java.io.IOException;import java.io.InputStream; import java.io ...
- kafka shutdown停止关闭很慢问题的解决方案
kafka shutdown停止很慢问题 在数据量大的时候,consumer一次抓取数据的数据很多,进入到业务处理的数据可能有很多, 假设一次poll有1万条数据进入业务程序,而且业务程序是和poll ...
- RPC的原理总结
一.RPC的引入 早期单机时代,一台电脑上运行多个进程,大家各干各的,老死不相往来.假如A进程需要一个画图的功能,B进程也需要一个画图的功能,程序员就必须为两个进程都写一个画图的功能.这不是整人么?于 ...
- wxformbuilder在python如何使用
1使用builder 创建界面并进行布局 2选择python选项 得到相应代码 将代码保存在 一个py文件里面 创建一个新的入口文件 main.py import wx import UIfile c ...
- window下安装绿色版5.7
1. 在mysql的安装目录下创建my.ini,并配置必要参数. 2. 执行命令mysqld --initialize-insecure --basedir=/opt/mysql/mysql --d ...
- C/C++和Lua是如何进行通信的?
为了实现Lua和其他语言之间的通信,Lua虚拟机为C/C++提供了两个特性: Lua_State状态机 lua_State主要是管理一个lua虚拟机的执行环境, 一个lua虚拟机可以有多个执行环境.L ...
- 第4章 Selenium2-java WebDriver API (二)
4.8 定位一组元素 定位一组元素的方法与定位单个元素的方法类似,唯一的区别是在单词element后面多了一个s表示复数.定位一组元素一般用于以下场景: ·批量操作元素,例如勾选页面上所有的复选框. ...
- PHP连接Memcache代码
<?php $mem = new Memcache; $mem->connect('127.0.0.1', 11211) or die ("Could not connect&q ...
- [NOI 2017]整数
Description 题库链接 P 博士将他的计算任务抽象为对一个整数的操作. 具体来说,有一个整数 \(x\) ,一开始为 \(0\) . 接下来有 \(n\) 个操作,每个操作都是以下两种类型中 ...
- 第4章 ext文件系统机制原理剖析
将磁盘进行分区,分区是将磁盘按柱面进行物理上的划分.划分好分区后还要进行格式化,然后再挂载才能使用(不考虑其他方法).格式化分区的过程其实就是创建文件系统. 文件系统的类型有很多种,如CentOS 5 ...