准备做一个禁言自动解除的功能,立马想到了订单的超时自动解除,刚好最近在看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延迟消息学习的更多相关文章

  1. Spring Boot RabbitMQ 延迟消息实现完整版

    概述 曾经去网易面试的时候,面试官问了我一个问题,说 下完订单后,如果用户未支付,需要取消订单,可以怎么做 我当时的回答是,用定时任务扫描DB表即可.面试官不是很满意,提出: 用定时任务无法做到准实时 ...

  2. RabbitMQ延迟消息的延迟极限是多少?

    之前在写Spring Cloud Stream专题内容的时候,特地介绍了一下如何使用RabbitMQ的延迟消息来实现定时任务.最近正好因为开发碰到了使用过程中发现,延迟消息没有效果,消息直接就被消费了 ...

  3. RabbitMQ延迟消息:死信队列 | 延迟插件 | 二合一用法+踩坑手记+最佳使用心得

    前言 前段时间写过一篇: # RabbitMQ:消息丢失 | 消息重复 | 消息积压的原因+解决方案+网上学不到的使用心得 很多人加了我好友,说很喜欢这篇文章,也问了我一些问题. 因为最近工作比较忙, ...

  4. RabbitMQ延迟消息队列实现定时任务完整代码示例

  5. Spring Cloud Stream 使用延迟消息实现定时任务(RabbitMQ)

    应用场景 通常在应用开发中我们会碰到定时任务的需求,比如未付款订单,超过一定时间后,系统自动取消订单并释放占有物品. 许多同学的第一反应就是通过spring的schedule定时任务轮询数据库来实现, ...

  6. 15-EasyNetQ之对延迟消息插件的支持

    RabbitMQ延迟消息插件仍然在实验阶段.你使用这个功能要自担风险. RabbitMQ延迟消息插件为RabbitMQ增加了新的交换机类型,允许延时消息投递. EasyNetQ为交换机通过定义一种新的 ...

  7. EasyNetQ使用(八)【对延迟消息插件的支持,自动订阅者】

    RabbitMQ延迟消息插件仍然在实验阶段.你使用这个功能要自担风险. RabbitMQ延迟消息插件为RabbitMQ增加了新的交换机类型,允许延时消息投递. EasyNetQ为交换机通过定义一种新的 ...

  8. rabbitmq学习(二):rabbitmq(消息队列)的作用以及rabbitmq之直连交换机

    前言 上篇介绍了AMQP的基本概念,组成及其与rabbitmq的关系.了解了这些东西后,下面我们开始学习rabbitmq(消息队列)的作用以及用java代码和rabbitmq通讯进行消息发布和接收.因 ...

  9. rabbitmq的延迟消息队列实现

    第一部分:延迟消息的实现原理和知识点 使用RabbitMQ来实现延迟任务必须先了解RabbitMQ的两个概念:消息的TTL和死信Exchange,通过这两者的组合来实现上述需求. 消息的TTL(Tim ...

随机推荐

  1. 聊聊我面试过的一个最奇葩的 Java 程序猿!

    上周我聊了聊最让我反感的 10 种程序猿,无奈一个小时就进行了删除,详细原因就不说了,容易招黑. 今天聊的我面试过的最奇葩的一个程序猿,绝对是奇葩中的奇葩,简直是程序猿中的另类,最让我反感的程序猿又添 ...

  2. js中数字直接点方法会报错,如1.toString()

    Number(11).toString() "11" var num = 111; undefined num.toString() "111" .toStri ...

  3. django rest framework serializers解读

    serializers是什么?官网是这样的"Serializers allow complex data such as querysets and model instances to b ...

  4. spring boot -thymeleaf-遍历list和map

    遍历 list如下 th:each th:each 状态变量 var 遍历map如下(需要双层遍历) controller代码如下

  5. Fiddler怎样抓取手机的包

    Fiddler作为代理服务器,可以拦截到手机发出的请求,再经过Fiddler发送到服务器,获取到服务器响应的数据,这个过程,只要设置配置好了,使用过程不受影响. 要想抓取到手机的包,先要给手机设置一个 ...

  6. VMware12 安装 Ubuntu18.04

    安装Ubuntu18.04虚拟机 Ubuntu获取地址: 官网:https://www.ubuntu.com/download/server 清华镜像站:https://mirrors.tuna.ts ...

  7. ES6中的proxy

    1 概述 Proxy 可以理解成,在目标对象之前架设一层“拦截”,外界对该对象的访问,都必须先通过这层拦截,因此提供了一种机制,可以对外界的访问进行过滤和改写. Proxy 这个词的原意是代理,用在这 ...

  8. canvas图片上传相关学习

    今天主要是研究了canvas的关于图片上传的相关知识, context.drawImage(img,sx,sy,swidth,sheight,x,y,width,height);  

  9. redis.properties

    #### env:${env} redis.maxIdle= ##最小空闲数 redis.minIdle= ##最大连接数:能够同时建立的“最大链接个数” redis.maxTotal= #每次最大连 ...

  10. Python循环文件推荐的方式,可用于读取文本最后一行或删除指定行等

    读取文本最后一行: f = open('test11.txt', 'rb') for i in f: offset = -16 while True: f.seek(offset, 2) data = ...