SpringBoot : ch11 整合RabbitMQ

前言

在当今的互联网时代,消息队列成为了构建高可靠、高性能系统的重要组件之一。RabbitMQ作为一个可靠、灵活的消息中间件,被广泛应用于各种分布式系统中。

本篇博客将介绍如何使用Spring Boot整合RabbitMQ,实现消息的发送和接收。通过这种方式,我们可以实现系统之间的解耦,提高系统的可靠性和扩展性。

在开始之前,我们需要先了解一些基本概念。RabbitMQ是一个基于AMQP(高级消息队列协议)的消息中间件,它采用了生产者-消费者模型。生产者负责发送消息到消息队列,而消费者则从队列中接收并处理消息。这种模型使得系统的各个组件可以并行工作,提高了系统的吞吐量和响应速度。

为了使用RabbitMQ,我们首先需要安装和配置它。RabbitMQ提供了丰富的功能和管理界面,可以通过简单的命令进行安装和配置。安装完成后,我们可以使用Spring Boot提供的RabbitMQ Starter来方便地集成RabbitMQ到我们的项目中。

本篇博客将从如何配置RabbitMQ开始,介绍如何创建生产者和消费者,并通过代码示例详细说明它们的使用方法。这个案例将展示如何通过消息队列传递订单信息。

一、安装RabbitMQ

教程地址:RabbitMQ 安装及配置-CSDN博客

 

二、RabbitMQ 基本概念

RabbitMQ是一个功能强大的开源消息中间件,它基于AMQP(Advanced Message Queuing Protocol,高级消息队列协议)实现了可靠的消息传递。在学习如何使用Spring Boot整合RabbitMQ之前,我们需要了解一些RabbitMQ的基本概念。

  1. 消息(Message):在RabbitMQ中,消息是指要传递的数据单元。它由一个消息体和一些可选的属性组成。消息体是实际要传递的数据,而属性则包含一些描述性的信息,例如消息的优先级、过期时间等。

  2. 生产者(Producer):生产者是消息的发送方。它负责将消息发送到RabbitMQ的交换机(exchange)中,并指定一个路由键(routing key)。交换机根据路由键将消息路由到一个或多个队列(queue)中。

  3. 交换机(Exchange):交换机是消息的分发中心,它接收从生产者发送的消息,并根据路由键将消息路由到一个或多个队列中。RabbitMQ提供了几种不同类型的交换机,包括直连交换机(direct exchange)、主题交换机(topic exchange)、扇形交换机(fanout exchange)和头交换机(headers exchange)。

  4. 队列(Queue):队列是消息的存储区域,用于存储交换机发送过来的消息。每个队列都有一个名称,并且可以绑定到一个或多个交换机上。消费者可以从队列中接收消息,并进行相应的处理。

  5. 消费者(Consumer):消费者是消息的接收方。它订阅一个或多个队列,并从队列中接收和处理消息。消费者可以以同步或异步的方式接收消息,可以手动确认消息的接收,也可以设置自动确认模式。

  6. 路由键(Routing Key):路由键是生产者在发送消息时指定的一个关键字。交换机根据路由键将消息路由到一个或多个队列中。不同类型的交换机对路由键的匹配规则有不同的要求。

以上是一些RabbitMQ的基本概念,了解这些概念对于理解和使用RabbitMQ非常重要。在后续的博客中,我们将深入探讨这些概念,并通过实际的代码示例演示它们的用法。

三、前期准备 

1、新建项目,结构如下

2、导入依赖
    <dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-amqp</artifactId></dependency><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency><dependency><groupId>org.springframework.amqp</groupId><artifactId>spring-rabbit-test</artifactId><scope>test</scope></dependency></dependencies><dependencyManagement><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-dependencies</artifactId><version>${spring-boot.version}</version><type>pom</type><scope>import</scope></dependency></dependencies></dependencyManagement><build><plugins><plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-compiler-plugin</artifactId><version>3.8.1</version><configuration><source>1.8</source><target>1.8</target><encoding>UTF-8</encoding></configuration></plugin><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId><version>${spring-boot.version}</version><configuration><mainClass>edu.nf.ch11.Ch11Application</mainClass><skip>true</skip></configuration><executions><execution><id>repackage</id><goals><goal>repackage</goal></goals></execution></executions></plugin></plugins></build>
  1. <dependencies>部分包含了项目的依赖项。在这里,你定义了项目所需的各种依赖库。例如,spring-boot-starter-amqp是Spring Boot提供的用于集成AMQP(包括RabbitMQ)的起步依赖,而lombok是一个Java库,可以通过注解来减少样板代码。另外,还有一些用于测试的依赖项,比如spring-boot-starter-testspring-rabbit-test

  2. <dependencyManagement>部分通常用来集中管理依赖项的版本号。在这个例子中,它引入了org.springframework.boot:spring-boot-dependencies这个POM文件,并指定了版本号${spring-boot.version}。这样一来,项目中引用的Spring Boot相关的依赖都会使用统一的版本号,便于管理。

  3. <build>部分包含了项目的构建配置。其中的<plugins>定义了Maven构建过程中需要使用的插件。比如,maven-compiler-plugin指定了Java编译器的版本和编码方式,而spring-boot-maven-plugin则用于打包Spring Boot应用。在这里,它被配置为跳过执行(<skip>true</skip>),因此在实际构建过程中不会执行打包操作。

这些配置文件是构建一个基于Spring Boot和RabbitMQ的应用所必需的,它们定义了项目的依赖项、构建方式以及其他相关设置.

四、配置 RabbitMQ 配置类


@Configuration
public class RabbitConfig {public static final String EXCHANGE_NAME = "test.exchange";public static final String QUEUE_NAME = "test.queue";public static final String ROUTER_KEY = "KEY.TEST";/*** 装配交换机* @return*/@Beanpublic DirectExchange exchange(){return new DirectExchange(EXCHANGE_NAME);}/*** 装配队列* @return*/@Beanpublic Queue queue(){return new Queue(QUEUE_NAME,false);}/*** 将队列绑定到交换机* @return*/@Beanpublic Binding binding(){return BindingBuilder.bind(queue()).to(exchange()).with(ROUTER_KEY);}/*** 装配自定义消息转换器* @return*/@Beanpublic MessageConverter messageConverter(){return new Jackson2JsonMessageConverter();}}

这段代码是一个用于配置RabbitMQ的类。让我解释一下其中的作用:

  1. @Configuration注解表示这是一个配置类,Spring会扫描该类并将其作为Bean定义加载到应用程序上下文中。

  2. exchange()方法使用@Bean注解将一个DirectExchange实例作为Bean加载到应用程序上下文中。DirectExchange是RabbitMQ中的一种类型的交换机,它通过指定的路由键将消息发送到与之匹配的队列。

  3. queue()方法使用@Bean注解将一个Queue实例作为Bean加载到应用程序上下文中。这个队列用于接收RabbitMQ中的消息。

  4. binding()方法使用@Bean注解将一个Binding实例作为Bean加载到应用程序上下文中。Binding用于将队列绑定到交换机并指定路由键。

  5. messageConverter()方法使用@Bean注解将一个MessageConverter实例作为Bean加载到应用程序上下文中。在这里,使用了Jackson2JsonMessageConverter,它是一个自定义的消息转换器,用于将消息以JSON格式进行序列化和反序列化。

通过使用这些Bean定义,你可以方便地配置RabbitMQ的交换机、队列、绑定关系以及消息转换器。

 

五、实体类

@Data
public class Order {private String orderId;}

 存放订单信息。

 

六、生产者代码


@Slf4j
@Service
@RequiredArgsConstructor
public class ProducerService {private final RabbitTemplate template;public void sendMessage(Order order){// 创建消息的唯一idCorrelationData correlationData = new CorrelationData();correlationData.setId(UUID.randomUUID().toString());// 发送消息template.convertAndSend(RabbitConfig.EXCHANGE_NAME,RabbitConfig.ROUTER_KEY,order,correlationData);// 确认发送成功template.setConfirmCallback((cdata,ack,cause) -> {if (ack){log.info("消息:" + cdata.getId() + "投递成功");}});}}

这段代码是一个名为ProducerService的服务类,使用了RabbitTemplate来发送消息到RabbitMQ消息队列。

在sendMessage方法中,首先创建了一个唯一的消息id,然后使用RabbitTemplate的convertAndSend方法将消息发送到指定的交换机(exchange)和路由键(routing key)。同时也传入了一个CorrelationData对象作为附加数据。

接着,通过设置RabbitTemplate的确认回调(confirm callback),可以确保消息的投递成功。在回调函数中,判断ack参数是否为true,如果为true,则表示消息投递成功,并打印相关日志信息。

 

七、消费者代码


@Slf4j
@Service
@RabbitListener(queues = RabbitConfig.QUEUE_NAME)
public class ConsumerService {@RabbitHandlerpublic void receive(Order order){log.info("处理订单:" + order.getOrderId());}}

 这段代码是一个消费者服务类,使用了@RabbitListener注解来监听名为RabbitConfig.QUEUE_NAME的队列。当队列中有消息到达时,会调用receive方法来处理接收到的消息。

在receive方法中,通过参数Order order来接收从队列中获取的订单消息,并打印处理订单的相关日志信息。

需要注意的是,@RabbitHandler注解用于标识该方法为消息处理方法,用来处理从队列中接收到的消息。同时,消费者需要配置好RabbitMQ的连接信息以及队列的绑定关系,确保能够正确地从指定的队列中接收消息并进行处理。

 

八、测试

1、在Rabbitmq的后台UI页面查看交换机

等下我们测试的时候,成功的话会产生一个新的交换机,我能现在查看就是为了确保等一下代码测试的结果。 

 2、测试结果
@Autowiredprivate ProducerService service;@Testvoid testSendMessage() {Order order = new Order();order.setOrderId("ABC123");service.sendMessage(order);}

这段代码是一个单元测试方法,用于测试ProducerService类中的sendMessage方法。首先通过@Autowired注解将ProducerService类注入到当前测试类中。

在testSendMessage方法中,创建了一个订单对象,并设置订单号为ABC123。接着调用service的sendMessage方法,将订单消息发送到RabbitMQ的消息队列中。

需要注意的是,由于这是一个单元测试方法,测试环境中需要正确配置RabbitMQ的连接信息、交换机和队列等信息,确保能够正常发送和接收消息。同时,在进行测试时,可以通过查看相关日志信息来确认消息是否成功发送和接收。

运行结果:

 

生产成功了,并且消费也成功了,我们去UI页面查看一下。 

3、查看后台的数据
 

有我们刚刚新添加的交换机。

 在消费的时候会有相应的信息显示。

这部分数据看起来是关于RabbitMQ中队列状态的概况。让我解释一下这些数据的含义:

  • Virtual host: 虚拟主机的名称。
  • Name: 队列的名称。
  • Type: 队列的类型,这里显示为 "classic",表示这是一个经典队列。
  • State: 队列的状态,这里显示为 "idle",表示队列处于空闲状态。
  • Ready: 队列中准备就绪的消息数量,这里显示为0。
  • Unacked: 未确认的消息数量,这里显示为0。
  • Total incoming: 总共进入队列的消息数量,这里显示为0.20条/秒。
  • Deliver / Get: 传递/获取消息的速率,这里显示为0.20条/秒。
  • Ack: 确认消息的速率,这里显示为0.20条/秒。

根据这些数据,队列目前处于空闲状态,但是有消息以每秒0.20条的速率进入队列,并以同样的速率被传递和确认。

注意:不会一直显示的,当消费完之后就会变回0了。

 

九、什么是RabbitMQ的生产者和消费者,区别是什么?

RabbitMQ是一种消息代理(message broker),用于在应用程序之间传递消息。在RabbitMQ中,生产者(producer)是发送消息的应用程序,而消费者(consumer)则是接收和处理这些消息的应用程序。

生产者将消息发布到一个交换机(exchange)中,交换机根据指定的路由键(routing key)将消息路由到一个或多个队列(queue)。消费者订阅这些队列,并从队列中获取消息进行处理。

在RabbitMQ中,生产者和消费者之间是解耦的,它们不需要直接知道对方的存在。生产者只需要知道如何将消息发送到正确的交换机中,而消费者只需要知道如何从正确的队列中获取消息进行处理。

使用RabbitMQ的优点是可以实现异步通信,提高系统的可伸缩性和可靠性。生产者和消费者之间的解耦也使得系统更加灵活和易于维护。

区别:

生产者(Producer)和消费者(Consumer)是在消息队列模式中的两个角色,它们有以下几个主要区别:

  1. 功能角色:生产者负责生成并发送消息到消息队列,它是消息的发送方;而消费者则从消息队列中接收并处理消息,它是消息的接收方。

  2. 数据流方向:在消息队列中,数据流是单向的。生产者将消息发布到消息队列,而消费者从消息队列中获取消息进行处理。生产者和消费者之间通过消息队列进行解耦,彼此不直接通信。

  3. 关注点不同:生产者关注的是如何生成并发送消息,通常是根据业务逻辑生成消息内容;消费者关注的是如何接收和处理消息,通常是基于业务需求对消息进行相应的处理操作。

  4. 并发性:在消息队列中,可以有多个生产者同时向一个队列发送消息,也可以有多个消费者同时从一个队列接收消息。这样可以实现消息的并发处理,提高系统的吞吐量和响应速度。

  5. 灵活性:由于生产者和消费者之间通过消息队列进行解耦,因此它们可以独立地进行扩展和部署。可以根据需要增加或删除生产者和消费者,而不会对整个系统造成影响。

总而言之,生产者负责生成和发送消息到消息队列,消费者负责接收和处理消息。它们在功能角色、数据流方向、关注点、并发性和灵活性等方面有所不同。通过合理使用生产者和消费者,可以实现高效的异步通信和解耦的系统架构。

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

基于SpringBoot的教师工作量管理系统

文章目录 项目介绍主要功能截图:部分代码展示设计总结项目获取方式🍅 作者主页:超级无敌暴龙战士塔塔开 🍅 简介:Java领域优质创作者🏆、 简历模板、学习资料、面试题库【关注我,都给你】 🍅文末获取源码联系🍅 项目介绍 基于SpringBoot的教师工作量管理系统,ja…

硬件工程师助理怎么买器件

1. 买器件的要求。 1. 保证器件的质量。 2. 货期近可能的合适。 3.稳定渠道。 2. 器件到哪里买 1. 首先到立创商城去买&#xff0c;因为方便&#xff0c;价格明显&#xff0c;质量有保证。 立创商城链接&#xff1a;新人注册享元器件优惠券_新人特价商品_立创商城 (szlcsc.com…

视频集中存储/磁盘阵列EasyCVR平台黑名单异常解决步骤是什么?

视频云存储/安防监控EasyCVR视频汇聚平台基于云边端智能协同&#xff0c;支持海量视频的轻量化接入与汇聚、转码与处理、全网智能分发、视频集中存储等。音视频流媒体视频平台EasyCVR拓展性强&#xff0c;视频能力丰富&#xff0c;具体可实现视频监控直播、视频轮播、视频录像、…

华为云(HECS)docker环境下安装jenkins

Jenkins是一个开源的自动化工具&#xff0c;可以自动化地完成构建、测试、交付或部署等任务。总之重点就是三个字&#xff1a;自动化&#xff0c;至于如何实现这些功能&#xff0c;Jenkins基于插件化的机制&#xff0c;提供了众多的插件来完成持续集成CI与持续部署CD。 【持续…

【Python】python天气数据抓取与数据分析(源码+论文)【独一无二】

&#x1f449;博__主&#x1f448;&#xff1a;米码收割机 &#x1f449;技__能&#x1f448;&#xff1a;C/Python语言 &#x1f449;公众号&#x1f448;&#xff1a;测试开发自动化【获取源码商业合作】 &#x1f449;荣__誉&#x1f448;&#xff1a;阿里云博客专家博主、5…

每日随想:在Python中字符串如何转列表

要将一个字符串转换为列表&#xff0c;可以使用字符串的 split() 方法。split() 方法根据指定的分隔符将字符串分割成子串&#xff0c;并将这些子串组成列表。 假设有一个用空格分隔的字符串&#xff0c;我们想要将其转换为一个单词列表&#xff1a; my_string "Hello w…

Ajax 是什么? 如何创建一个 Ajax?

Ajax&#xff08;Asynchronous JavaScript and XML&#xff09;是一种使用客户端JavaScript发送异步HTTP请求到服务器的技术&#xff0c;以便在不重新加载整个页面的情况下更新部分网页内容。 使用Ajax的原因有很多&#xff0c;以下是其中一些&#xff1a; 改善用户体验&…

pdf文件能扫码查看吗?一键做文本二维码

pdf格式是常用的一种文件格式&#xff0c;很多资料、展示性的内容都会选择这种格式&#xff0c;现在很多人都需要将文件生成二维码图片后分享给他人&#xff0c;那么文件存入二维码展示的方法有哪些呢&#xff1f;下面给大家分享一招使用二维码生成器来生成二维码图片的操作方法…

[英语学习][3][Word Power Made Easy]的精读与翻译优化

[序言] 这次翻译校验, 难度有点大, 原版中英翻译已出现了严重地偏差. 昨晚11点开始阅读如下段落, 花费了1个小时也没有理解原作者的核心表达, 索性睡觉了. 今早学习完朗文单词之后, 9点半开始继续揣摩. 竟然弄到了中午11点30, 终于明白原作者要表达的意思了. 废话不多说&#x…

插入排序:理解经典的排序技术

什么是插入排序&#xff1f; 插入排序是一种简单而直观的排序算法&#xff0c;它的工作方式类似于我们手动排序卡片或整理文件&#xff1a; 工作原理&#xff1a; 初始状态&#xff1a;将数组分为两部分&#xff1a;一部分是已排序的&#xff08;最开始时这部分只包含第一个元…

SVD recommendation systems

SVD recommendation systems 为什么在推荐系统中使用SVD 一个好的推荐系统一定有小的RMSE R M S E 1 m ∑ i 1 m ( Y i − f ( x i ) 2 RMSE \sqrt{\frac{1}{m} \sum_{i1}^m(Y_i-f(x_i)^2} RMSEm1​i1∑m​(Yi​−f(xi​)2 ​ 希望模型能够在已知的ratings上有好的结果的…

[学习笔记]IK分词器的学习

IK分词器有几种模式 # 测试分词器 POST /_analyze {"text":"黑马程序员学习java太棒了","analyzer": "standard" }# 测试分词器 POST /_analyze {"text":"黑马程序员学习java太棒了","analyzer": &quo…

电脑风扇转一下停一下,无法正常开机问题解决

今天同事电话说电脑开不了机了&#xff0c;只听见风扇不停地呜呜地作响。笔者第一反应是不是硬件哪里出问题了&#xff0c;于是二话没说拿起心爱的螺丝刀就闪了过去。 按下电源&#xff0c;确实如电话所述。但感觉风扇并非一直在转&#xff0c;而是时断时续。由于听不大真切&a…

怎么更新BI报表数据?问我就对了

BI大数据分析工具上有大量的BI报表模板&#xff0c;这些模板都是一个个完整的BI报表&#xff0c;只需将数据源更换&#xff0c;立即就能用来分析我们自己的数据。那&#xff0c;BI报表的数据怎么更新&#xff1f;接下来就来说说这事。 目的&#xff1a;更新BI报表数据 工具&a…

第3章 表、栈和队列

前言 本章讨论最简单和最基本的三种数据结构。实际上&#xff0c;每一个有意义的程序都将至少明确使用一种这样的数据结构&#xff0c;而栈则在程序中总是隐含使用&#xff0c;不管你在程序中是否做了声明。 在这一章&#xff0c;我们将&#xff1a; 介绍抽象数据类型…

每日OJ题_算法_双指针⑧力扣18. 四数之和

目录 力扣18. 四数之和 解析代码 力扣18. 四数之和 难度 中等 给你一个由 n 个整数组成的数组 nums &#xff0c;和一个目标值 target 。请你找出并返回满足下述全部条件且不重复的四元组 [nums[a], nums[b], nums[c], nums[d]] &#xff08;若两个四元组元素一一对应&…

nvm:node版本控制工具

下载安装 首先先下载nvm&#xff0c;下载地址 https://github.com/coreybutler/nvm-windows/releases选择nvm-setup.exe下载即可 常用命令 命令说明nvm list available显示所有可以下载的Node.js版本nvm list显示已安装的版本nvm install 18.12.1安装18.12.1版本的Node.jsnv…

如何把一个数组json数据,加到已有的树形数据中

要将一个数组的 JSON 数据添加到已有的树形数据中&#xff0c;可以使用递归方法遍历树形数据&#xff0c;并将数组中的每个元素插入到合适的位置。以下是一个使用 JavaScript 实现的示例&#xff1a; function insertArrayToTree(tree, arrayData) {if (!tree || !arrayData) …

Pikachu靶场(PHP反序列化漏洞)

查看php反序列化漏洞的概述&#xff0c;了解序列化与反序列化。 构造payload <?php class S{var $test "<script>alert(wjy)</script>"; } $c new S(); echo(serialize($c)); ?>将对象序列化为O:1:"S":1:{s:4:"test";s:…

【Linux下基本指令——(1)】

Linux下基本指令——&#xff08;1&#xff09; 一. ls 指令1.1.语法&#xff1a;1.2.功能&#xff1a;1.3.常用选项&#xff1a;1.4.举例&#xff1a;1.5.Xshell7展示 二. pwd 命令2.1.语法: 2.2.功能&#xff1a;2.3.常用选项&#xff1a;2.4.Xshell7展示 三. cd 指令3.1.语法…