Springboot整合RabbitMQ并使用
1、Springboot整合RabbitMQ
1、引入场景启动器
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-amqp</artifactId>
</dependency>
引入AMQP场景启动器之后,RabbitAutoConfiguration
就会自动生效。然后会给容器中自动配置了RabbitTemplate
、AmqpAdmin
、CachingConnectionFactory
、RabbitMessagingTemplate
等来方便使用AMQP。
2、在yml中配置spring.rabbitmq相关信息
spring:rabbitmq:host: 192.168.56.10port: 5672username: adminpassword: adminvirtual-host: my_vhost
2、简单使用
2.1 创建交换机(Exchange)、队列(Queue)和建立绑定关系(Binding)
@SpringBootTest
public class AmqpAdminTest {@Autowiredprivate AmqpAdmin amqpAdmin;/*** 1、如何创建Exchange、Queue、Binding* 1)、使用AmqpAdmin进行创建*/@Testpublic void creatExchange() {//创建 名为 itcxc.java.direct 的交换机DirectExchange directExchange = new DirectExchange("itcxc.java.direct");amqpAdmin.declareExchange(directExchange);}@Testpublic void creatQueue() {//创建名为 itcxc.java 的队列Queue queue = new Queue("itcxc.java");amqpAdmin.declareQueue(queue);}@Testpublic void creatBinding() {//创建绑定关系 将队列itcxc.java绑定到交换机itcxc.java.direct,routingKey为itcxc.javaBinding binding = new Binding("itcxc.java", Binding.DestinationType.QUEUE,"itcxc.java.direct","itcxc.java",null);amqpAdmin.declareBinding(binding);}
}
2.1.1 交换机类型:
direct
:会将消息发送给路由键必须完全匹配的队列中。
fanout
:会将消息发送给所有绑定的队列中,不管路由键是否匹配。
topic
:主体模式其实就是在路由模式的基础上,支持了对key的通配符匹配(星号以及井号),以满足更加复杂的消息分发场景。(#
匹配零个或者多个单词,*
匹配一个单词,每个单词用.
分割)
2.2 发送消息
@SpringBootTest
public class RabbitTemplateTest {@Autowiredprivate RabbitTemplate rabbitTemplate;/*** 2、如何发消息* 1)、使用rabbitTemplate发送消息*/@Testpublic void sendMessageTest(){OrderReturnReasonEntity orderReturnReasonEntity = new OrderReturnReasonEntity();orderReturnReasonEntity.setId(1L);orderReturnReasonEntity.setName("哈哈");orderReturnReasonEntity.setCreateTime(new Date());//1、发送消息// 默认情况下,如果发送的消息是一个对象,我们会使用序列化机制,将对象写出去,对象必须实现Serializable接口// 但是我们可以通过向容器中注入Jackson2JsonMessageConverter转换器将序列化机制改为转JSONrabbitTemplate.convertAndSend("itcxc.java.direct","itcxc.java", orderReturnReasonEntity);}
}
2.2.1 替换消息系列化方式
通过观看RabbitTemplate
的源码发现,我们在默认情况下消息系列化方式是JDK序列化方式。那么我们发送的消息如果是一个对象时,这个对象就必须实现Serializable
接口。
如何使用转JSON的方式序列化消息呢?
通过观察RabbitAutoConfiguration
源码发现,在创建RabbitTemplate
的时候,会从容器中拿消息序列化器(MessageConverter)。
所以我们想要将转JSON的方式序列化消息,只需要给容器中放一个Jackson2JsonMessageConverter
就可以了
@Component
public class GulimallRabbitMqConfig {/*** 消息转换器 指定消息转换的方式为转为JSON* @return*/@Beanpublic MessageConverter messageConverter(){return new Jackson2JsonMessageConverter();}}
2.3 获取消息
2.3.1 在启动类或者配置类上添加@EnableRabbit注解
使用@RabbitListener
必须开启@EnableRabbit
,如果没有使用@RabbitListener
可以不添加@EnableRabbit
注解。
2.3.2 添加@RabbitListener
@RabbitListener
:可以标注在类和方法上 (监听哪些队列)
@RabbitHandler
:只能标注在方法上 (重载区别不同的消息)
@Service
public class RabbitListeners {/*** queues:声明需要监听的所有队列** 接收参数的类型:* 1、org.springframework.amqp.core.Message* 2、直接写原来发送的消息类型* 3、Channel 当前传送数据的通道** @param message*/@RabbitListener(queues = {"itcxc.java"})public void receiveMessage(Message message, OrderReturnReasonEntity orderReturnReasonEntity,Channel channel){System.out.println("接收到的消息为:" + orderReturnReasonEntity);}
}
现在有一个情况,就是我们给同一个消息对象发送的消息是有可能不是同一个类型的。例如:
@Test
public void sendMq(){for (int i = 0; i < 10; i++) {if (i % 2 == 0){OrderReturnReasonEntity orderReturnReasonEntity = new OrderReturnReasonEntity();orderReturnReasonEntity.setId(1L);orderReturnReasonEntity.setName("哈哈");orderReturnReasonEntity.setCreateTime(new Date());rabbitTemplate.convertAndSend("itcxc.java.direct","itcxc.java", orderReturnReasonEntity);} else {OrderEntity orderEntity = new OrderEntity();orderEntity.setOrderSn(UUID.randomUUID().toString());rabbitTemplate.convertAndSend("itcxc.java.direct","itcxc.java", orderEntity);}}
}
在这个情况下如果我们还是用原来的方式监听消息的话,就会使发送的消息类型为OrderEntity
的消息丢失。
这个时候我们就可以,将@RabbitListener
标注在类上,然后@RabbitHandler
标注在方法上
@Service
@RabbitListener(queues = {"itcxc.java"})
public class RabbitListeners {/*** queues:声明需要监听的所有队列** 接收参数的类型:* 1、org.springframework.amqp.core.Message* 2、直接写原来发送的消息类型* 3、Channel 当前传送数据的通道** @param message*/@RabbitHandlerpublic void receiveMessage(Message message, OrderReturnReasonEntity orderReturnReasonEntity,Channel channel){System.out.println("接收到的消息为:" + orderReturnReasonEntity);}@RabbitHandlerpublic void receiveMessage(OrderEntity orderEntity){System.out.println("接收到的消息为:" + orderEntity);}
}
3、消息的可靠传递
3.1 发送端确认
为什么会丢失消息?
- 在发送消息到服务端的时候,有可能因为网络等等问题,没有将消息发送到服务端。
- 在
交换机(Exchange)
通过路由键将消息发送给队列(Queue)
的时候有可能没有找到相应的队列(Queue)
,而默认情况下是将消息直接丢弃的。
3.1.1 开启confirm和return机制
spring:rabbitmq:# 消息发送到broker后的回调 publisher-confirm-type: correlated# 没有设置mandatory时生效publisher-returns: true# mandatory的优先级高于publisher-returns,只要设置了mandatory,publisher-returns就失效了template:mandatory: true
我翻看源码可以发现mandatory
的优先级高于publisher-returns
,只要设置了mandatory
,publisher-returns
就失效了。
但是经过测试,我发现mandatory
,只有在publisher-confirm-type
、publisher-returns
至少有一个设置才会生效。如果mandatory
、publisher-returns
同时存在的话,则mandatory
优先级高于publisher-returns
。
3.1.2 添加回调方法
@Component
@RequiredArgsConstructor
public class RabbitMqCallback {private final RabbitTemplate rabbitTemplate;/*** RabbitMqCallback 创建完成之后,执行这个方法* @return*/@PostConstructpublic RabbitTemplate initCallback() {/*** 需要设置spring.rabbitmq.publisher-confirm-type=correlated* 消息发broker成功回调:发送到broker的exchange是否正确找到* correlationData:当前消息的唯一关联数据(这个是消息的唯一ID)* ack:消息是否发送成功* cause:失败的原因,成功则返回null*/rabbitTemplate.setConfirmCallback((correlationData, ack, cause) -> {System.out.println("setConfirmCallback 消息数据:" + correlationData);if (Objects.nonNull(correlationData)) {System.out.println("setConfirmCallback 消息数据:" + correlationData.getReturnedMessage());}System.out.println("setConfirmCallback 消息确认:" + ack);System.out.println("setConfirmCallback 原因:" + cause);System.out.println("-----------------------------------");});/*** 需要设置spring.rabbitmq.template.mandatory=true或spring.rabbitmq.publisher-returns=true 才会有回调* 消息路由回调:从交换器路由到队列是否正确发送* message:投递失败消息的详细消息* replyCode:回应码* replyText:回应信息* exchange:当时这个消息发送给的交换器* routingKey:当时这个消息发送用的路由键*/rabbitTemplate.setReturnCallback((message, replyCode, replyText, exchange, routingKey) -> {System.out.println("setReturnCallback 消息:" + message);System.out.println("setReturnCallback 回应码:" + replyCode);System.out.println("setReturnCallback 回应信息:" + replyText);System.out.println("setReturnCallback 交换器:" + exchange);System.out.println("setReturnCallback 路由键:" + routingKey);System.out.println("-----------------------------------");});return rabbitTemplate;}
}
这样我们就可以知道哪些消息发送成功,哪些消息发送失败了,然后就可以做出相应的处理。
3.2 消费端确认
为什么会丢失消息?
默认情况下只要收到消息,客户端会自动确认,然后服务端就会移除这个消息。由于客户端会一次性接收很多的消息。
在这个情况下,就有可能我们接收了10个消息,只处理了前面2个消息,然后服务宕机了,这样就会使得我们有8个消息丢失。
3.2.1 设置ACK应答机制为手动
spring:rabbitmq:# 设置ACK应答机制为手动listener:simple:acknowledge-mode: manual
手动模式,只要我们没有明确的告诉MQ,消息被签收(没有ACK),消息就是一直处于unacked状态,即使客户端宕机了,消息也不会丢失,会重新变为ready,下次有新的客户端连接进来就发给新的客户端。
3.2.2 处理完消息之后手动应答
@RabbitListener(queues = {"itcxc.java"})public void receiveMessage(Message message, OrderReturnReasonEntity orderReturnReasonEntity,Channel channel) throws IOException {//deliveryTag通道(channel)内自增的long deliveryTag = message.getMessageProperties().getDeliveryTag();System.out.println("方法一deliveryTag为"+deliveryTag+"接收到的消息为:" + orderReturnReasonEntity);//确认签收参数说明(deliveryTag,是否批量签收)channel.basicAck(deliveryTag,false);//拒绝签收参数说明(deliveryTag,是否批量签收,是否放回队列中)//channel.basicNack(deliveryTag,false,true);}
相关文章:

Springboot整合RabbitMQ并使用
1、Springboot整合RabbitMQ 1、引入场景启动器 <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-amqp</artifactId> </dependency>引入AMQP场景启动器之后,RabbitAutoConfiguratio…...

Java中方法引用(引用静态方法、引用成员方法(引用其他类的成员方法、引用本类的成员方法、引用父类的成员方法)、引用构造方法、其他调用方式、小练习)
方法引用:把已经存在的方法拿过来用,当作函数式接口中抽象方法的方法体 我们前面学到Arrays工具类中的sort方法,当我们需要指定排序规则时,需要传递Comparator接口的实现类对象,我们之前使用匿名内部类类的形式作为参…...
整理了100道关于Python基础知识的练习题,记得收藏~
实例1.数字组合 题目: 有四个数字:1、2、3、4,能组成多少个互不相同且无重复数字的三位数?各是多少? 程序分析: 遍历全部可能,把有重复的剃掉。 total0 for i in range(1,5):for j in range(…...
OSG三维渲染引擎编程学习之七十七:“第七章:OSG场景图形交互” 之 “7.8 场景交互”
目录 第七章 OSG场景图形交互 7.8 场景交互 7.8.1 osgGA库 7.8.2 事件消息处理 7.8.3 程序抓图示例...
797.差分
输入一个长度为 n的整数序列。 接下来输入 m个操作,每个操作包含三个整数 l,r,c,表示将序列中 [l,r] 之间的每个数加上 c。 请你输出进行完所有操作后的序列。 输入格式 第一行包含两个整数 n和 m。 第二行包含 n个整数,表示整数序列。 …...

为什么说要慎用BeanUtils,因为性能真的拉跨
1 背景之前在专栏中讲过“不推荐使用属性拷贝工具”,推荐直接定义转换类和方法使用 IDEA 插件自动填充 get / set 函数。不推荐的主要理由是:有些属性拷贝工具性能有点差有些属性拷贝工具有“BUG”使用属性拷贝工具容易存在一些隐患(后面例子…...

【项目设计】高并发内存池(六)[细节优化+测试]
🎇C学习历程:入门 博客主页:一起去看日落吗持续分享博主的C学习历程博主的能力有限,出现错误希望大家不吝赐教分享给大家一句我很喜欢的话: 也许你现在做的事情,暂时看不到成果,但不要忘记&…...

同模块设置不同应用主题方案
有时候公司内部会有不同应用但是有部分模块功能一样,只根据应用角色有些细节逻辑区分的场景。这时候往往采用模块化采用以应用至不同的APP。如果APP主题不一致,该如果解决。 方案: 在不同应用的config.gradle 下面根据不同应用定义不同的a…...

centos7 安装 hyperf
PHP > 7.4 Swoole PHP 扩展 > 4.5,并关闭了 Short Name OpenSSL PHP 扩展 JSON PHP 扩展 PDO PHP 扩展 Redis PHP 扩展 Protobuf PHP 扩展 composer create-project hyperf/hyperf-skeleton 推荐安装项 全部选n php.ini [swoole] extens…...

RZ/G2UL核心板-40℃低温启动测试
1. 测试对象HD-G2UL-EVM基于HD-G2UL-CORE工业级核心板设计,一路千兆网口、一路CAN-bus、 3路TTL UART、LCD、WiFi、CSI 摄像头接口等,接口丰富,适用于工业现场应用需求,亦方便用户评估核心板及CPU的性能。HD-G2UL-CORE系列工业级核…...

PyQt5可视化 7 饼图和柱状图实操案例 ①Qt项目的创建
目录 一、新建Qt项目 二、添加组件和布局 三、添加资源 1. 新建资源文件 2. 添加图标资源 四、frameHead 1. toolBtnGenData 2. toolBtnCounting 3. comboTheme 4. comboAnimation 5. Horizontal Spacer 6. toolBtnQuit 7. 设置toolBtnQuit的功能 8. frameHead的…...

0104路径搜索和单点路径-无向图-数据结构和算法(Java)
文章目录2 单点路径2.1 API2.2 算法实现后记2 单点路径 单点路径。给定一幅图和一个起点s,回答“从s到给定的目的顶点v是否存在一条路径?如果有,找出这条路径。”等类似问题。 2.1 API 单点路径问题在图的处理邻域中十分重要。根据标准设计…...

Maxscale读写分离实施文档
Maxscale介绍 MaxScale是maridb开发的一个mysql数据中间件,其配置简单,能够实现读写分离,并且可以根据主从状态实现写库的自动切换。 使用Maxscale无需对业务代码进行修改,其自带的读写分离模块,能够解析SQL语句&…...
websocket实现一个简单聊天框
websoket在客户端的使用 事件:open/message/error/close 方法:send/close var socket new WebSocket(url)// 服务连接成功时触发 socket.addEventListener(open, function() {console.log("连接成功了") })// 主动给websocket发消息 socket…...
Docker-安装应用
一、安装Tomcat 注意:新版Tomcat安装之后启动访问会出现404 修改:删除原有的webapps目录,修改webapps.dist为webapps 免修改版本:billygoo/tomcat8-jdk8 二、安装Mysql 1、安装 拉取镜像 docker pull mysql:5.7 运行镜像…...

Web3中的营销:如何在2023年获得优势
Mar. 2022, Daniel在过去的一年里,让人们对你的Web3项目或协议感兴趣已经变得越来越有挑战性。许多曾经充满希望的项目因为各种不同的原因,都在熊市中倒下了。然而,那些迄今为止幸存下来的项目都有一个共同点:强大的社区。Web3营销…...
Java中==和equals区别
文章目录Java中和equals区别1. Integer中和equals的问题1.1 Integer类型且不是通过new创建的比较1.2 手动new Integer()创建的比较1.3 Integer和int比较2. String中和equals的问题3. DemoJava中和equals区别 equals是方法,是运算符: 如果比较的对象是基…...

计算机科学导论笔记(三)
五、计算机组成 计算机组成部件可以分为三大类(子系统):中央处理单元(CPU)、主存储器和输入/输出子系统。 5.1 中央处理单元(CPU) 中央处理单元用于数据的运算,分为算术逻辑单元&a…...

Stream——数字类型的字符串排序
文章目录前言什么是数字类型的字符串一个简单的坑demo拯救坑代码对象集合中的数字类型排序(有坑)对象集合中的数字类型排序 解决扩展将数字类型字符串数组转换为Integer集合总结前言 想到给数据进行排序,一开始头脑中想到的就是sorted(),本篇文章重点说…...

.NET 8 预览版 1 发布!
.NET 8 是一个长期支持(LTS) 版本。这篇文章涵盖了推动增强功能优先级排序和选择开发的主要主题和目标。.NET 8 预览版和发布候选版本将每月交付一次。像往常一样,最终版本将在 11 月的某个时候在 .NET Conf 上发布。 .NET 版本包括产品、库、运行时和工具…...
RestClient
什么是RestClient RestClient 是 Elasticsearch 官方提供的 Java 低级 REST 客户端,它允许HTTP与Elasticsearch 集群通信,而无需处理 JSON 序列化/反序列化等底层细节。它是 Elasticsearch Java API 客户端的基础。 RestClient 主要特点 轻量级ÿ…...

中南大学无人机智能体的全面评估!BEDI:用于评估无人机上具身智能体的综合性基准测试
作者:Mingning Guo, Mengwei Wu, Jiarun He, Shaoxian Li, Haifeng Li, Chao Tao单位:中南大学地球科学与信息物理学院论文标题:BEDI: A Comprehensive Benchmark for Evaluating Embodied Agents on UAVs论文链接:https://arxiv.…...
基础测试工具使用经验
背景 vtune,perf, nsight system等基础测试工具,都是用过的,但是没有记录,都逐渐忘了。所以写这篇博客总结记录一下,只要以后发现新的用法,就记得来编辑补充一下 perf 比较基础的用法: 先改这…...

PL0语法,分析器实现!
简介 PL/0 是一种简单的编程语言,通常用于教学编译原理。它的语法结构清晰,功能包括常量定义、变量声明、过程(子程序)定义以及基本的控制结构(如条件语句和循环语句)。 PL/0 语法规范 PL/0 是一种教学用的小型编程语言,由 Niklaus Wirth 设计,用于展示编译原理的核…...

嵌入式学习笔记DAY33(网络编程——TCP)
一、网络架构 C/S (client/server 客户端/服务器):由客户端和服务器端两个部分组成。客户端通常是用户使用的应用程序,负责提供用户界面和交互逻辑 ,接收用户输入,向服务器发送请求,并展示服务…...
Redis:现代应用开发的高效内存数据存储利器
一、Redis的起源与发展 Redis最初由意大利程序员Salvatore Sanfilippo在2009年开发,其初衷是为了满足他自己的一个项目需求,即需要一个高性能的键值存储系统来解决传统数据库在高并发场景下的性能瓶颈。随着项目的开源,Redis凭借其简单易用、…...

CVPR2025重磅突破:AnomalyAny框架实现单样本生成逼真异常数据,破解视觉检测瓶颈!
本文介绍了一种名为AnomalyAny的创新框架,该方法利用Stable Diffusion的强大生成能力,仅需单个正常样本和文本描述,即可生成逼真且多样化的异常样本,有效解决了视觉异常检测中异常样本稀缺的难题,为工业质检、医疗影像…...
Leetcode33( 搜索旋转排序数组)
题目表述 整数数组 nums 按升序排列,数组中的值 互不相同 。 在传递给函数之前,nums 在预先未知的某个下标 k(0 < k < nums.length)上进行了 旋转,使数组变为 [nums[k], nums[k1], …, nums[n-1], nums[0], nu…...

JDK 17 序列化是怎么回事
如何序列化?其实很简单,就是根据每个类型,用工厂类调用。逐个完成。 没什么漂亮的代码,只有有效、稳定的代码。 代码中调用toJson toJson 代码 mapper.writeValueAsString ObjectMapper DefaultSerializerProvider 一堆实…...

MySQL体系架构解析(三):MySQL目录与启动配置全解析
MySQL中的目录和文件 bin目录 在 MySQL 的安装目录下有一个特别重要的 bin 目录,这个目录下存放着许多可执行文件。与其他系统的可执行文件类似,这些可执行文件都是与服务器和客户端程序相关的。 启动MySQL服务器程序 在 UNIX 系统中,用…...