SpringBoot使用消息队列RabbitMQ
RabbitMQ 即一个消息队列,主要是用来实现应用程序的异步和解耦,同时也能起到消息缓冲、消息分发的作用。RabbitMQ是实现AMQP(高级消息队列协议)的消息中间件的一种,AMQP,即Advanced Message Queuing Protocol, 高级消息队列协议,是应用层协议的一个开放标准,为面向消息的中间件设计。在项目中,将一些无需即时返回且耗时的操作提取出来,进行了异步处理,而这种异步处理的方式大大的节省了服务器的请求响应时间, 提高了系统的吞吐量。
简单概念
几个名词术语:
Broker - 简单来说就是消息队列服务器的实体。
Exchange - 消息路由器,转发消息到绑定的队列上,指定消息按什么规则,路由到哪个队列。
Queue - 消息队列,用来存储消息,每个消息都会被投入到一个或多个队列。
Binding - 绑定,它的作用就是把 Exchange 和 Queue 按照路由规则绑定起来。
RoutingKey - 路由关键字,Exchange 根据这个关键字进行消息投递。
Producter - 消息生产者,产生消息的程序。
Consumer - 消息消费者,接收消息的程序。
Channel - 消息通道,在客户端的每个连接里可建立多个Channel,每个channel代表一个会话。
一般消息队列都是生产者(Producter)将消息发送到队列(Queue),消费者(Consumer)监听队列进行消费。rabbitmq中一个虚拟主机(默认 /)持有一个或者多个交换机(Exchange)。 用户只能在虚拟主机的粒度进行权限控制,交换机根据一定的策略(RoutingKey)绑定(Binding)到队列(Queue)上, 这样生产者和队列就没有直接联系,而是将消息发送的交换机,交换机再把消息转发到对应绑定的队列上。
交换机(Exchange)作为RabbitMQ的一个重要概念,最常用的有四种类型:
Direct: 先匹配, 再投送。即在绑定时设定一个routing_key, 消息的routing_key匹配时, 才会被交换器投送到绑定的队列中去. 交换机跟队列必须是精确的对应关 系,这种最为简单。
Topic: 转发消息主要是根据通配符。在这种交换机下,队列和交换机的绑定会定义一种路由模式,那么,通配符就要在这种路由模式和路由键之间匹配后交换 机才能转发消息,这种可以认为是Direct 的灵活版
Headers: 也是根据规则匹配, 相较于 direct 和 topic 固定地使用 routingkey , headers则是一个自定义匹配规则的类型, 在队列与交换器绑定时会设定一组键值 对规则,消息中也包括一组键值对( headers属性),当这些键值对有一对或全部匹配时,消息被投送到对应队列。
Fanout : 消息广播模式,不管路由键或者是路由模式,会把消息发给绑定给它的全部队列,如果配置了routingkey会被忽略
Ack机制
在RabbitMQ的消息队列编程中,有个非常重要的概念叫消息确认机制,也就是Ack机制。每个Consumer可能需要一段时间才能处理完收到的数据。如果在这个过程中,Consumer出错了或者异常退出了,而数据还没有处理完成,那么非常不幸,这段数据就丢失了。因为我们采用no-ack的方式进行确认,也就是说,每次Consumer接到数据后,而不管是否处理完成,RabbitMQ Server会立即把这个Message标记为完成,然后从queue中删除了。 如果一个Consumer异常退出了,它处理的数据能够被另外的Consumer处理,这样数据在这种情况下就不会丢失了。
为了保证数据不被丢失,RabbitMQ支持消息确认机制,即acknowledgments。为了保证数据能被正确处理而不仅仅是被Consumer收到,那么我们不能采用no-ack。而应该是在处理完数据后发送ack。 在处理数据后发送的ack,就是告诉RabbitMQ数据已经被接收,处理完成,RabbitMQ可以去安全的删除它了。
如果Consumer退出了但是没有发送ack,那么RabbitMQ就会把这个Message发送到下一个Consumer。这样就保证了在Consumer异常退出的情况下数据也不会丢失。
这里并没有用到超时机制。RabbitMQ仅仅通过Consumer的连接中断来确认该Message并没有被正确处理。也就是说,RabbitMQ给了Consumer足够长的时间来做数据处理。 这样即使你通过Ctr-C中断了Recieve.cs,那么Message也不会丢失了,它会被分发到下一个Consumer。如果忘记了ack,那么后果很严重。当Consumer退出时,Message会重新分发。然后RabbitMQ会占用越来越多的内存,由于RabbitMQ会长时间运行,因此这个“内存泄漏”是致命的。
下面的例子使用手动Ack模式
1.环境准备:
RabbitMQ需要安装erlang和RabbitMQ Server
erlang是一种通用的面向并发的编程语言 ,RabbitMQ则是由其编写,下载地址:http://www.erlang.org/downloads
RabbitMQ Server 下载地址 :http://www.rabbitmq.com/install-windows.html
安装完成后,会发现:
此时,RabbitMQ并未启动,可通过手动点击 rabbitmq_server-3.7.9\sbin 目录下的 rabbitmq-plugins.bat 来启动 ;
也可以通过命令行来添加可视化启动界面:
创建用户名密码和分配权限:
①查看用户
②添加用户名和密码
③添加角色和权限
最后 ,访问http://localhost:15672/ ,输入用户密码
2.SpringBoot中集成
maven依赖
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-amqp</artifactId>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.9.</version>
</dependency> <dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<exclusions>
<exclusion>
<groupId>com.vaadin.external.google</groupId>
<artifactId>android-json</artifactId>
</exclusion>
</exclusions>
</dependency>
</dependencies>
配置文件
##########################################################
################## 所有profile共有的配置 #################
########################################################## ################### spring配置 ###################
spring:
profiles:
active: dev --- #####################################################################
######################## 开发环境profile ##########################
#####################################################################
spring:
profiles: dev
rabbitmq:
host: 127.0.0.1
port: 5672
username: spring
password: 123456
publisher-confirms: true #支持发布确认
publisher-returns: true #支持发布返回
listener:
simple:
acknowledge-mode: manual #采用手动应答
concurrency: 1 #指定最小的消费者数量
max-concurrency: 1 #指定最大的消费者数量
retry:
enabled: true #是否支持重试 logging:
level:
ROOT: INFO
com:
xncoding: DEBUG
file: D:/logs/app.log #日志路径
配置类
最核心的类就是RabbitMQ的配置类,在里面定制模版类、声明交换机、队列、绑定交换机到队列。这里声明了一个Direct类型的交换机,并通过路由键绑定到一个队列中来测试Direct模式, 另外还声明了Fanout类型的交换机,并绑定到2个队列来测试广播模式;
监听器
编写消息队列的监听器类,监听队列消息并做相应的处理,并通过Ack机制确认处理完成:
@Component
public class Receiver {
private static final Logger log = LoggerFactory.getLogger(Receiver.class); /**
* FANOUT广播队列监听一.
*
* @param message the message
* @param channel the channel
* @throws IOException the io exception 这里异常需要处理
*/
@RabbitListener(queues = {"FANOUT_QUEUE_A"})
public void on(Message message, Channel channel) throws IOException {
channel.basicAck(message.getMessageProperties().getDeliveryTag(), true);
log.debug("FANOUT_QUEUE_A " + new String(message.getBody()));
} /**
* FANOUT广播队列监听二.
*
* @param message the message
* @param channel the channel
* @throws IOException the io exception 这里异常需要处理
*/
@RabbitListener(queues = {"FANOUT_QUEUE_B"})
public void t(Message message, Channel channel) throws IOException {
channel.basicAck(message.getMessageProperties().getDeliveryTag(), true);
log.debug("FANOUT_QUEUE_B " + new String(message.getBody()));
} /**
* DIRECT模式.
*
* @param message the message
* @param channel the channel
* @throws IOException the io exception 这里异常需要处理
*/
@RabbitListener(queues = {"DIRECT_QUEUE"})
public void message(Message message, Channel channel) throws IOException {
channel.basicAck(message.getMessageProperties().getDeliveryTag(), true);
log.debug("DIRECT " + new String(message.getBody()));
}
}
消息发送者
再写一个消息发送服务,用来向交换机发送消息:
/**
* 消息发送服务
*/
@Service
public class SenderService {
private Logger logger = LoggerFactory.getLogger(this.getClass());
@Resource
private RabbitTemplate rabbitTemplate; /**
* 测试广播模式.
*
* @param p the p
* @return the response entity
*/
public void broadcast(String p) {
CorrelationData correlationData = new CorrelationData(UUID.randomUUID().toString());
rabbitTemplate.convertAndSend("FANOUT_EXCHANGE", "", p, correlationData);
} /**
* 测试Direct模式.
*
* @param p the p
* @return the response entity
*/
public void direct(String p) {
CorrelationData correlationData = new CorrelationData(UUID.randomUUID().toString());
rabbitTemplate.convertAndSend("DIRECT_EXCHANGE", "DIRECT_ROUTING_KEY", p, correlationData);
} }
运行测试
@RunWith(SpringRunner.class)
@SpringBootTest(classes = Application.class)
public class SenderServiceTest {
@Autowired
private SenderService senderService; @Test
public void testCache() {
// 测试广播模式
senderService.broadcast("同学们集合啦!");
// 测试Direct模式
senderService.direct("定点消息"); }
}
测试结果
代码下载地址:https://pan.baidu.com/s/1fAvUM3XKIqvFAZwk7c1YvA
SpringBoot使用消息队列RabbitMQ的更多相关文章
- C#中使用消息队列RabbitMQ
在C#中使用消息队列RabbitMQ 2014-10-27 14:41 by qy1141, 745 阅读, 2 评论, 收藏, 编辑 1.什么是RabbitMQ.详见 http://www.rabb ...
- node使用消息队列RabbitMQ一
基础发布和订阅 消息队列RabbitMQ使用 1 安装RabbitMQ服务器 安装erlang服务 下载地址 http://www.erlang.org/downloads 安装RabbitMQ 下载 ...
- 消息队列--RabbitMQ(一)
1.消息队列概述 可以理解为保存消息的一个媒介/或者是个容器,与之相关有两个概念(即生产者(Publish)与消费者(Consumer)).所谓生产者,就是生产创造消息的一方,那么,消费者便是从队列中 ...
- (二)RabbitMQ消息队列-RabbitMQ消息队列架构与基本概念
原文:(二)RabbitMQ消息队列-RabbitMQ消息队列架构与基本概念 没错我还是没有讲怎么安装和写一个HelloWord,不过快了,这一章我们先了解下RabbitMQ的基本概念. Rabbit ...
- (一)RabbitMQ消息队列-RabbitMQ的优劣势及产生背景
原文:(一)RabbitMQ消息队列-RabbitMQ的优劣势及产生背景 本篇并没有直接讲到技术,例如没有先写个Helloword.我想在选择了解或者学习一门技术之前先要明白为什么要现在这个技术而不是 ...
- ASP.NET Core消息队列RabbitMQ基础入门实战演练
一.课程介绍 人生苦短,我用.NET Core!消息队列RabbitMQ大家相比都不陌生,本次分享课程阿笨将给大家分享一下在一般项目中99%都会用到的消息队列MQ的一个实战业务运用场景.本次分享课程不 ...
- 消息队列rabbitmq/kafka
12.1 rabbitMQ 1. 你了解的消息队列 rabbitmq是一个消息代理,它接收和转发消息,可以理解为是生活的邮局.你可以将邮件放在邮箱里,你可以确定有邮递员会发送邮件给收件人.概括:rab ...
- nodejs操作消息队列RabbitMQ
一. 什么是消息队列 消息队列(Message Queue,简称MQ),从字面意思上看,本质是个队列,FIFO先入先出,只不过队列中存放的内容是message而已.其主要用途:不同进程Process/ ...
- 消息队列rabbitmq rabbitMQ安装
消息队列rabbitmq 12.1 rabbitMQ 1. 你了解的消息队列 生活里的消息队列,如同邮局的邮箱, 如果没邮箱的话, 邮件必须找到邮件那个人,递给他,才玩完成,那这个任务会处理的很麻 ...
随机推荐
- 【Python 18】BMR计算器2.0(数值类型转换与while循环)
1.案例描述 基础代谢率(BMR):我们安静状态下(通常为静卧状态)消耗的最低热量,人的其他活动都建立在这个基础上. 计算公式: BMR(男) = (13.7*体重kg)+(5.0*身高cm)-(6. ...
- gulp配置(编译压缩转码自动刷新注释全)
参考自:http://www.sheyilin.com/2016/02/gulp_introduce/ 在原先基础上增加了less编译 es6转码资源地图等,修改了一部分的热刷新. gulpfile. ...
- Python编码规范(PEP8)及奇技淫巧(不断更新)
https://blog.csdn.net/MrLevo520/article/details/69155636
- python基础-小练习
三级菜单 要求: 打印省.市.县三级菜单 可返回上一级 可随时退出程序 购物车程序 要求: 用户名和密码存放于文件中,格式为:egon|egon123 启动程序后,先登录,登录成功则让用户输入工资,然 ...
- android系统中如何通过程序打开某个AccessibilityService
android系统中如何通过程序打开某个AccessibilityService(系统辅助服务)? 通常的做法是注册AccessibilityService(辅助服务)后跳转到设置启动服务页面引导用户 ...
- Do You Kown Asp.Net Core - 根据实体类自动创建Razor Page CURD页面模板
Scaffolding Template Intro 我们知道在Asp.Net MVC中,如果你使用的EF的DBContext的话,你可以在vs中通过右键解决方案-添加控制器-添加包含视图的控制器,然 ...
- vue axios封装以及登录token过期跳转问题
Axios配置JWT/封装插件/发送表单数据 首先请务必已仔细阅读 Axios 文档并熟悉 JWT: 中文文档 JWT 中文文档 安装 npm install axios npm install es ...
- web 日历 任务 插件
[2] 日历任务插件(jquery版)新增日历任务和点击监听 - qq_26462567的博客 - CSDN博客https://blog.csdn.net/qq_26462567/article/de ...
- VUE 绑定背景图片的写法
<div v-bind:style='{"background-image":"url("+imgUrl+")"}' >< ...
- vue非父子组件之间的通信
https://www.cnblogs.com/chengduxiaoc/p/7099552.html //vm.$emit( event, arg ) //触发当前实例上的事件 //vm.$on ...