准备做一个禁言自动解除的功能,立马想到了订单的超时自动解除,刚好最近在看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. vue中axios的安装和使用

    有很多时候你在构建应用时需要访问一个 API 并展示其数据.做这件事的方法有好几种,而使用基于 promise 的 HTTP 客户端 axios 则是其中非常流行的一种. 安装包:如果没有安装cnpm ...

  2. 转载:https原理:证书传递、验证和数据加密、解密过程解析

    写的太好了,就是我一直想找的内容,看了这个对https立马明白多了 http://www.cnblogs.com/zhuqil/archive/2012/07/23/2604572.html 我们都知 ...

  3. Spring Cloud 微服务分布式链路跟踪 Sleuth 与 Zipkin

    Zipkin 是一个开放源代码分布式的跟踪系统,由 Twitter 公司开源,它致力于收集服务的定时数据,以解决微服务架构中的延迟问题,包括数据的收集.存储.查找和展现.它的理论模型来自于Google ...

  4. 使用maven构建多模块项目,分块开发

    在多人使用Maven协作开发项目时,尤其是稍微上点规模的项目,每个RD的工作都细分到具体功能和模块,有些模块甚至还要单独部署. 我们假设有这样一个商城项目,包括以下几个模块: 商城前台(shop) 管 ...

  5. 通过清华大学镜像下载Android源码并编译源码

    之前看源码都是在Windows下用SourceInsight看,虽然达到了研究源码的效果,但终究还是有遗憾...趁着周末,准备在Ubuntu虚拟机上下载编译源码. 之前下源码时,有了解一些Androi ...

  6. vs2015+qt5.9.7配置跨平台的工程

    环境:vs2015 update 3 + qt 5.9.7 问题:代码中存在中文无法编译 附加目的:支持跨平台 问题分析:代码的编码格式导致中文编译错误,windows默认gb2312编码,qt默认u ...

  7. 百度编辑器 UEditor setContent()

    给编辑器赋值的代码: var ue = UE.getEditor('content'); ue.ready(function (){      ue.setContent(data.data.cont ...

  8. php获取当前是星期几

    <?php $weekarray=array("日","一","二","三","四",&quo ...

  9. 牛刀小试MySQL--GTID

    GTID的概念 何为GITD GTID(global transaction identifier)是全局事务标识符,在MySQL5.6版本中作为一个超级特性被推出.事务标识不仅对于Master(起源 ...

  10. VS2012使用验证控件出现[ASP.NET]WebForms UnobtrusiveValidationMode 需要 'jquery' 的 ScriptResourceMapping。請加入 ScriptResourceMapping 命名的 jquery (區分大小寫)。的解决办法。

    方法一:在webconfig中找到 <appSettings><add key="aspnet:UseTaskFriendlySynchronizationContext& ...