Spring Boot 整合 RabbitMQ 实现延迟消息

关于 RabbitMQ

消息队列(Message Queuing,简写为 MQ)最初是为了解决金融行业的特定业务需求而产生的。慢慢的,MQ 被应用到了更多的领域,然而商业 MQ 高昂的价格让很多初创公司望而却步,于是 AMQP(Advanced Message Queuing Protocol,高级消息队列协议)应运而生。

随着 AMQP 草案的发布,两个月后,RabbitMQ 1.0 就发布了。

RabbitMQ 的架构模型可以分为客户端和服务端两部分,客户端包括生产者和消费者,服务端包括虚拟主机、交换器和队列。

整体的流程非常简单,生产者将消息发送到服务端,消费者从服务端获取对应的消息。

生产者在发送消息前需要先确认发送给哪个虚拟主机的哪个交换器,再由交换器通过路由键将消息转发给与之绑定的队列。

最后,消费者到指定的队列中获取自己的消息进行消费。

客户端

生产者和消费者都属于客户端。

生产者:消息的发送方,将要发送的消息封装成一定的格式,发送给服务端。消息包括消息体和标签。

消费者:消息的接收方,负责消费消息体。

服务端

虚拟主机、交换机、队列都属于服务端。

虚拟主机:用来对交换器和队列进行逻辑隔离,在同一个虚拟主机下,交换器和队列的名称不能重复。有点类似 Java 中的包,同一个包下,不能有相同名称的类或者接口。

交换器:负责接收生产者发来的消息,并根据规则分配给对应的队列,不生产消息,只是消息的搬运工。

队列:负责存储消息,生产者发送的消息会放在这里,消费者从这里取。

连接和信道

连接和信道是两个不同的概念,连接的英文叫 connection,信道叫 channel。

连接里包含了多条信道,连接用的是 TCP 连接,因为 AMQP 就是用 TCP 实现的。

为什么不直接使用连接,而要在连接的基础上新建信道呢?

因为 TCP 连接是比较昂贵的,新建需要三次握手,销毁需要四次挥手,所以如果每个线程在想 RabbitMQ 服务端发送/接收消息的时候都新建一个 TCP 连接,就会非常的消耗资源,于是就有了信道。

信道是线程私有的,连接是线程共享的。

信道+连接的模式,既保证了线程之间的私密性,又减少了系统开销。

业务场景

消息队列的主要功能有三种:

  • 异步处理,比如说在做电商业务的时候,提交订单的动作可能涉及到创建订单、扣除库存、增加用户积分、发送订单邮件等。它们并不是一个串行的操作,可以把发送订单邮件和增加用户积分交给消息队列去做。
  • 系统解耦,消息队列可以作为不同系统之间的桥梁,且不受系统技术栈的约束。
  • 缓冲削峰,消息队列可以将大量的请求放到队列中,然后再按照一定的顺序规则交给业务服务器处理。

工作模式

RabbitMQ 支持 7 种工作模式:

  • 简单模式
  • 工作队列模式
  • 广播模式
  • 路由模式
  • 动态路由模式
  • 远程模式
  • 生产者确认模式

我们这里只演示前三种,

简单模式

简单模式真的超级简单,生产者将消息发送给队列,消费者从队列中获取消息队列即可。

生活中就类似于 快递员将包裹放到快递柜,然后给取件人发一个取件码,取件人通过取件码去快递柜里取包裹📦。

工作队列模式

工作队列模式在本质上只比简单模式对了一个队列,消费者从一个变成了多个。生产者将消息放入到队列中,多个消费者会一次进行消费。

比如说有 3 个消费者,生产者向队列发送 3 条消息,3 个消费者会没人消费一条消息,有点雨露均沾的意味。

当然了,也可以通过配置,将其改成能者多劳的模式。

广播模式

与工作队列模式不同,广播模式就有交换器参与了。在广播模式下,即使生产者只生产了一条消息,它对应的所有消费者都能全部接收,真正做到了公平公正公开。

安装配置 RabbitMQ

RabbitMQ 的安装方式可以参考官方:

Installing RabbitMQ | RabbitMQ

  • 服务器数据统计——消息投递情况,以及连接、信道、交换器、队列、消费者的数量
  • RabbitMQ 节点信息——erlang 进程、内存、磁盘空间等
  • 端口和 Web 信息
  • 。。。

启动RabbitMQ服务。

rabbitmq-server.bat

我们点击 admin 面板 点击虚拟主机新建一个 codingmore 的虚拟主机。

并新建一个用户 admin:

并设置它的权限。

整合 RabbitMQ

第一步,在 pom.xml 文件中添加 RabbitMQ 的 starter 依赖。

<dependency>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-amqp</artifactId>
</dependency>

第二步,在 application.yml 文件中添加 RabbitMQ 的配置。

spring:
  rabbitmq:
    host: 127.0.0.1
    port: 5672
    username: admin
    password: admin
    virtual-host: codingmore

简单模式

第三步,新建 RabbitMQController 控制器类,添加 sendSimple 生产者接口。

@RestController
@Api(tags = "整合 RabbitMQ")
@RequestMapping("/rabbitmq")
public class RabbitMQController {
    @Autowired
    private RabbitTemplate rabbitTemplate;

    @PostMapping("/sendSimple")
    @ApiOperation("简单模式")
    public ResultObject sendSimple(String routingKey, String message) {
        rabbitTemplate.convertAndSend(routingKey, message);
        return ResultObject.success("ok");
    }
}

RabbitTemplate 是 Spring Boot 为我们封装好的操作 RabbitMQ 的工具类。

第四步,新建 SimpleConsumer 类,添加简单模式的消费者。

@Slf4j
@Component
@RabbitListener(queuesToDeclare = @Queue("simple"))
public class SimpleConsumer {
    @RabbitHandler
    public void receive(String message) {
        log.info("简单模式:{}", message);
    }
}

启动服务,在浏览器地址栏访问 http://localhost:8080/doc.html 打开 Swagger。

输入参数,点击发送。

在Intellij IDEA 中可以看到输出信息。

这就表示我们完成了 RabbitMQ 的简单模式。

工作队列模式

在 RabbitMQController 控制器中添加 sendWork 工作队列接口:

@PostMapping("/sendWork")
@ApiOperation("工作队列模式")
public ResultObject sendWork(String routingKey, String message) {
    for (int i = 0; i < 10; i++) {
        rabbitTemplate.convertAndSend(routingKey, "第" + i + "消息:" + message);
    }
    return ResultObject.success("ok");
}

新建 WorkConsumer 类,添加工作队列模式的消费者。

@Slf4j
@Component
public class WorkConsumer {
    @RabbitListener(queuesToDeclare = @Queue("work"))
    public void receiveOne(String message) {
        log.info("工作队列模式 receiveOne:{}", message);
    }

    @RabbitListener(queuesToDeclare = @Queue("work"))
    public void receiveTwo(String message) {
        log.info("工作队列模式 receiveTwo:{}", message);
    }
}

build 服务,在浏览器地址栏打开 http://localhost:8080/doc.html 刷新 Swagger。

输入参数,点击发送。

在Intellij IDEA 中可以看到输出信息。

这就表示我们完成了 RabbitMQ 的工作队列模式。

广播模式

在 RabbitMQController 控制器中添加 sendBroadcast 广播接口:

@PostMapping("/sendBroadcast")
@ApiOperation("广播模式")
public ResultObject sendBroadcast(String exchange, String message) {
    rabbitTemplate.convertAndSend(exchange, "",message);
    return ResultObject.success("ok");
}

新建 BroadcastConsumer 类,添加广播模式的消费者。

@Slf4j
@Component
public class BroadcastConsumer {
    @RabbitListener(bindings = @QueueBinding(value = @Queue,
            exchange = @Exchange(name = "fanout", type = "fanout")))
    public void receiveOne(String message) {
        log.info("广播模式 receiveOne:{}", message);
    }

    @RabbitListener(bindings = @QueueBinding(value = @Queue,
            exchange = @Exchange(name = "fanout", type = "fanout")))
    public void receiveTwo(String message) {
        log.info("广播模式 receiveTwo:{}", message);
    }
}

注意这里的 Exchange(交换器)名字要是 fanout,它是 RabbitMQ 默认的一种交换器。

Fanout模式不需要处理路由键(所以我们在 sendBroadcast 接口中,convertAndSend 方法中传递的 routingKey 是空的),我们只需要简单的将队列绑定到exchange上,发送到exchange的每一个消息都会被转发到与该exchange绑定的所有队列上。

Fanout类型的Exchange转发消息是最快的。除此之外,还有 Direct Exchange、Topic Exchange,大家可以去了解一下。

build 服务,在浏览器地址栏打开 http://localhost:8080/doc.html 刷新 Swagger。

输入参数,点击发送。

在Intellij IDEA 中可以看到输出信息。

可以看到两个消费者都消费了消息,这就表示我们完成了 RabbitMQ 的广播模式。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/516918.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

点亮创意:ChatGPT如何搭桥DALL-E图像编辑新纪元

每周跟踪AI热点新闻动向和震撼发展 想要探索生成式人工智能的前沿进展吗&#xff1f;订阅我们的简报&#xff0c;深入解析最新的技术突破、实际应用案例和未来的趋势。与全球数同行一同&#xff0c;从行业内部的深度分析和实用指南中受益。不要错过这个机会&#xff0c;成为AI领…

金融中的数学知识

随机偏微分方程相比普通偏微分方程具有额外的随机项&#xff0c;反映了其描述的现象具有随机性质

在ArcGIS Pro中优雅的制作荧光图

最近在网上看到了荧光图&#xff0c;觉得挺帅气&#xff0c;去网上查询了怎么制作荧光图&#xff0c;发现大部分都是QGIS的教程&#xff0c;作为ArcGIS的死忠用户&#xff0c;决定在ArcGIS Pro中实现&#xff0c;其实挺简单的。 1、软件&#xff1a;ArcGIS Pro3.0 2、点数据&a…

Linux的软链接和硬链接

1、软链接 概念&#xff1a;给文件创建一个快捷方式&#xff0c;依赖原文件&#xff0c;和普通文件没有区别。 特性&#xff1a; 可以给存在的文件或目录创建软链接可以给不存在的文件或目录创建软链接可以跨文件系统创建软链接删除软链接不影响原文件、删除原文件会导致软链…

【Java基础】Java基础知识整合

文章目录 1. 转义字符2. 变量2.1 字符串与整型相加2.2 byte和short的区别2.3 float和double的区别2.4 char类型2.5 boolean类型2.6 自动类型转换及运算2.7 强制类型转换2.8 String的转换2.9 除法运算2.10 取模规则 3. 自增4. 逻辑运算符5. 赋值运算 6. 三元运算符&#xff1a;7…

一文介绍回归和分类的本质区别 !!

文章目录 前言 1、回归和分类的本质 &#xff08;1&#xff09;回归&#xff08;Regression&#xff09;的本质 &#xff08;2&#xff09;分类&#xff08;Classification&#xff09;的本质 2、回归和分类的原理 &#xff08;1&#xff09;回归&#xff08;Regression&#x…

力扣 115. 不同的子序列

题目来源&#xff1a;https://leetcode.cn/problems/distinct-subsequences/description/ C题解&#xff1a;动态规划。 dp[i][j] 表示 t[0] ~ t[i-1] 在 s[0] ~ s[j-1] 中出现的个数。因为 t 短&#xff0c;所以把 t 放在外循环。 当 t[i-1] 不等于 s[j-1] 时&#xff0c;s[…

认识 Redis 与 分布式

Redis 官网页面 Redis官网链接 Redis 的简介 Redis 是一个在内存中存储数据的中间件 一方面用于作为数据库&#xff0c;另一方面用于作为数据缓存&#xff0c;适用于分布式系统中 Redis 基于网络&#xff0c;进行进程间通信&#xff0c;把自己内存中的变量给别的进程&#xf…

深度解析GPT中的Tokenizer

继学习完深度解析大语言模型中的词向量后&#xff0c;让我们继续学习大语言模型中另外几个重要概念&#xff1a;token&#xff08;词元&#xff09;、tokenization&#xff08;词元化&#xff09;、tokenizer&#xff08;词元生成器&#xff09;。 在GPT模型中&#xff0c;toke…

【与C++的邂逅之旅】--- 内联函数 auto关键字 基于范围的for循环 nullptr

关注小庄 顿顿解馋૮(˶ᵔ ᵕ ᵔ˶)ა 博主专栏&#xff1a; &#x1f4a1; 与C的邂逅之旅 &#x1f4a1; 数据结构之旅 上篇我们了解了函数重载和引用&#xff0c;我们继续学习有关C的一些小语法— 内联函数&#xff0c;auto关键字&#xff0c;基于范围的for循环以及 nullptr&…

设计模式——建造者模式03

工厂模式注重直接生产一个对象&#xff0c;而建造者模式 注重一个复杂对象是如何组成的&#xff08;过程&#xff09;&#xff0c;在生产每个组件时&#xff0c;满足单一原则&#xff0c;实现了业务拆分。 设计模式&#xff0c;一定要敲代码理解 组件抽象 public interface …

02---webpack基础用法

01 entry打包的入口文件&#xff1a; 单入口entry是一个字符串:适用于单页面项目module.exports {entry:./src/index.js}多入口entry是一个对象module.exports {entry:{index:./src/index.js,app:./src/app.js}} 02 output打包的出口文件&#xff1a; 单入口配置module.ex…

【opencv】教程代码 —video(3) 视频背景剔除

bg_sub.cpp 这段代码的功能是把视频中的背景和前景分离&#xff0c;提取出前景的运动物体。根据用户选择的不同的模式&#xff0c;可以选择基于MOG2或者基于KNN的方法来进行背景减除。在处理每一帧图像的过程中&#xff0c;首先使用背景减除模型对图像帧进行处理&#xff0c;得…

RabbitMQ3.7.8集群分区(脑裂现象)模拟及恢复处置全场景测试

测试环境准备: MQ服务器集群地址&#xff0c;版本号为3.7.8&#xff1a; 管理控制台地址:http://173.101.4.6:15672/#/queues 集群状态 rabbitmqctl cluster_status 集群操作相关命令: 创建一个RabbitMQ集群涉及到如下步骤&#xff1a; 安装RabbitMQ&#xff1a; 在每台要在集…

JVM专题——类文件加载

本文部分内容节选自Java Guide和《深入理解Java虚拟机》, Java Guide地址: https://javaguide.cn/java/jvm/class-loading-process.html &#x1f680; 基础&#xff08;上&#xff09; → &#x1f680; 基础&#xff08;中&#xff09; → &#x1f680;基础&#xff08;下&a…

利用AI结合无极低码(免费版)快速实现接口开发教程,会sql即可,不需要编写编译代码

无极低码无代码写服务+AI实践 本次演示最简单的单表无代码增删改查发布服务功能,更复杂的多表操作,安全验证,多接口调用,自自动生成接口服务,生成二开代码,生成调用接口测试,一键生成管理界面多条件检索、修改、删除、查看、通用公共接口调用、通用无限级字典调用等后续…

【Linux】Ubuntu 文件权限管理

Linux 系统对文件的权限有着严格的控制&#xff0c;用于如果相对某个文件执行某种操作&#xff0c;必须具有对应的权限方可执行成功&#xff0c;这也是Linux有别于Windows的机制&#xff0c;也是基于这个权限机制&#xff0c;Linux可以有效防止病毒自我运行。因为运行的条件是必…

第二十三章 Git

一、Git Git 是一个开源的分布式版本控制系统&#xff0c;用于敏捷高效地处理任何或小或大的项目。 Git 是 Linus Torvalds 为了帮助管理 Linux 内核开发而开发的一个开放源码的版本控制软件。 Git 与常用的版本控制工具 CVS, Subversion 等不同&#xff0c;它采用了分布式版…

前端三剑客 —— CSS ( 坐标问题 、定位问题和图片居中 )

前期内容回顾&#xff1a; 1.常见样式 text-shadow x轴 y轴 阴影的模糊程度 阴影的颜色 box-shadow border-radio 实现圆角 margin 内边距 padding 外边距 background 2.特殊样式 媒体查询&#xff1a;media 自定义字体&#xff1a;font-face { font-family:自定义名称&#…

代码随想录算法训练营第四十四天 |卡码网52. 携带研究材料 、518. 零钱兑换 II、377. 组合总和 Ⅳ

代码随想录算法训练营第四十四天 |卡码网52. 携带研究材料 、518. 零钱兑换 II、377. 组合总和 Ⅳ 卡码网52. 携带研究材料题目解法 518. 零钱兑换 II题目解法 377. 组合总和 Ⅳ题目解法 感悟 卡码网52. 携带研究材料 题目 解法 题解链接 1. #include <iostream> #inc…