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 版本包括产品、库、运行时和工具…...
变量 varablie 声明- Rust 变量 let mut 声明与 C/C++ 变量声明对比分析
一、变量声明设计:let 与 mut 的哲学解析 Rust 采用 let 声明变量并通过 mut 显式标记可变性,这种设计体现了语言的核心哲学。以下是深度解析: 1.1 设计理念剖析 安全优先原则:默认不可变强制开发者明确声明意图 let x 5; …...
Spark 之 入门讲解详细版(1)
1、简介 1.1 Spark简介 Spark是加州大学伯克利分校AMP实验室(Algorithms, Machines, and People Lab)开发通用内存并行计算框架。Spark在2013年6月进入Apache成为孵化项目,8个月后成为Apache顶级项目,速度之快足见过人之处&…...
工程地质软件市场:发展现状、趋势与策略建议
一、引言 在工程建设领域,准确把握地质条件是确保项目顺利推进和安全运营的关键。工程地质软件作为处理、分析、模拟和展示工程地质数据的重要工具,正发挥着日益重要的作用。它凭借强大的数据处理能力、三维建模功能、空间分析工具和可视化展示手段&…...
AI编程--插件对比分析:CodeRider、GitHub Copilot及其他
AI编程插件对比分析:CodeRider、GitHub Copilot及其他 随着人工智能技术的快速发展,AI编程插件已成为提升开发者生产力的重要工具。CodeRider和GitHub Copilot作为市场上的领先者,分别以其独特的特性和生态系统吸引了大量开发者。本文将从功…...
有限自动机到正规文法转换器v1.0
1 项目简介 这是一个功能强大的有限自动机(Finite Automaton, FA)到正规文法(Regular Grammar)转换器,它配备了一个直观且完整的图形用户界面,使用户能够轻松地进行操作和观察。该程序基于编译原理中的经典…...
Yolov8 目标检测蒸馏学习记录
yolov8系列模型蒸馏基本流程,代码下载:这里本人提交了一个demo:djdll/Yolov8_Distillation: Yolov8轻量化_蒸馏代码实现 在轻量化模型设计中,**知识蒸馏(Knowledge Distillation)**被广泛应用,作为提升模型…...
IP如何挑?2025年海外专线IP如何购买?
你花了时间和预算买了IP,结果IP质量不佳,项目效率低下不说,还可能带来莫名的网络问题,是不是太闹心了?尤其是在面对海外专线IP时,到底怎么才能买到适合自己的呢?所以,挑IP绝对是个技…...
Python Einops库:深度学习中的张量操作革命
Einops(爱因斯坦操作库)就像给张量操作戴上了一副"语义眼镜"——让你用人类能理解的方式告诉计算机如何操作多维数组。这个基于爱因斯坦求和约定的库,用类似自然语言的表达式替代了晦涩的API调用,彻底改变了深度学习工程…...
Linux部署私有文件管理系统MinIO
最近需要用到一个文件管理服务,但是又不想花钱,所以就想着自己搭建一个,刚好我们用的一个开源框架已经集成了MinIO,所以就选了这个 我这边对文件服务性能要求不是太高,单机版就可以 安装非常简单,几个命令就…...
深度剖析 DeepSeek 开源模型部署与应用:策略、权衡与未来走向
在人工智能技术呈指数级发展的当下,大模型已然成为推动各行业变革的核心驱动力。DeepSeek 开源模型以其卓越的性能和灵活的开源特性,吸引了众多企业与开发者的目光。如何高效且合理地部署与运用 DeepSeek 模型,成为释放其巨大潜力的关键所在&…...
