Rabbitmq消息队列详解(三)——SpringBoot整合

news2025/4/12 8:36:31

SpringBoot整合

依赖:

<!-- 加入rabbitmq -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-amqp</artifactId>
</dependency>

配置:

spring:
  application:
    name: rabbitmq-springboot

  rabbitmq:
    host: 192.168.169.135
    port: 5672
    username: root
    password: 123456
    virtual-host: wzq.host #虚拟主机,最好名字是/开头,rabbitmq中先创建

配置会自动配置到RabbitTemplate,直接注入使用即可。

队列和交换机的创建是在消费者处创建的,如果没有消费者,队列和交换机不会创建。

//@Payload Object message消息是实体类的json数据

hello模型

没有交换机,直接发消息到队列

生产者:

    @Resource
    private RabbitTemplate rabbitTemplate;

    //发送到hello队列
    @Test
    public void hello(){
        rabbitTemplate.convertAndSend("hello","hello world!");
    }

消费者:

@Component
@RabbitListener(queuesToDeclare = @Queue(value = "hello"/**,durable = "true",autoDelete = "true"**/))
//消费者,监听hello队列,没有队列就创建,默认配置是持久化、非独占、不是自动删除
public class HelloCustomer {

    @RabbitHandler
    public void receice1(String message){
        System.out.println("message = " + message);
    }

}

任务模型

没有交换机,多个消费者,轮询平均分配给消息者

生产者:

    @Resource
    private RabbitTemplate rabbitTemplate;

    //发送到work队列
    @Test
    public void work(){
        for (int i = 0; i < 10; i++) {
            rabbitTemplate.convertAndSend("work",i+"work模型!");
        }
    }

消费者:

@Component
public class WorkCustomer {

    //多个消费者

    @RabbitListener(queuesToDeclare = @Queue("work"))
    public void receive1(String message){
        System.out.println("message1 = " + message);
    }

    @RabbitListener(queuesToDeclare = @Queue("work"))
    public void receive2(String message){
        System.out.println("message2 = " + message);
    }

}

在这里插入图片描述

fanout模型

交换机把所有消息都分配到每一个与它绑定的队列中,路由key没意义

生产者:

    @Resource
    private RabbitTemplate rabbitTemplate;

    //fanout广播模型
    @Test
    public void fanout(){
        //交换机、路由key、内容
        rabbitTemplate.convertAndSend("logs","","fanout模型!");
    }

消费者:

@Component
public class FanoutCustomer {

    //多个消费者

    @RabbitListener(bindings = {
            @QueueBinding(
                    //@Queue("名字")不写名字则创建一个临时队列,写就创建对应名字的队列
                    value = @Queue,
                    exchange = @Exchange(value = "logs", type = "fanout") //交换机名字跟消费者一样
            )
    })
    public void receive1(String message){
        System.out.println("message1 = " + message);
    }

    @RabbitListener(bindings = {
            @QueueBinding(
                    //@Queue("名字")不写名字则创建一个临时队列
                    value = @Queue,
                    exchange = @Exchange(value = "logs", type = "fanout") //交换机名字跟消费者一样
            )
    })
    public void receive2(String message){
        System.out.println("message2 = " + message);
    }
}

在这里插入图片描述

direct模型

路由key指定消息队列,队列key和消息key一致就接收消息

生产者:

    @Resource
    private RabbitTemplate rabbitTemplate;

    //direct路由模型
    @Test
    public void direct(){
        //交换机、路由key、内容
        rabbitTemplate.convertAndSend("directs","info","direct模型info消息!");
    }

消费者:

@Component
public class DirectCustomer {

    @RabbitListener(bindings = {
            @QueueBinding(
                    value = @Queue("direct"), 
                    exchange = @Exchange(value = "directs"),  //默认类型就是type
                    key = {"info","error","warning"}
            )
    })
    public void receive1(String message){
        System.out.println("message1 = " + message);
    }

    @RabbitListener(bindings = {
            @QueueBinding(
                    value = @Queue, //临时队列
                    exchange = @Exchange(value = "directs"),  //默认类型就是type
                    key = {"info"}
            )
    })
    public void receive2(String message){
        System.out.println("message2 = " + message);
    }

}

只接收对应key的消息

topic模型

*指匹配单个,#指匹配所有

生产者:

    @Resource
    private RabbitTemplate rabbitTemplate;

    //topic动态路由模型
    @Test
    public void topic(){
        //交换机、路由key、内容
        rabbitTemplate.convertAndSend("topics","user.save","topic模型user.save消息!");
    }

消费者:

@Component
public class TopicCustomer {

    @RabbitListener(bindings = {
            @QueueBinding(
                    value = @Queue,
                    exchange = @Exchange(value = "topics",type = "topic"),  //默认类型就是type
                    key = {"user.save","user.*"}
            )
    })
    public void receive1(String message){
        System.out.println("message1 = " + message);
    }

    @RabbitListener(bindings = {
            @QueueBinding(
                    value = @Queue,
                    exchange = @Exchange(value = "topics",type = "topic"),  //默认类型就是type
                    key = {"order.#","produce.#","user.*"}
            )
    })
    public void receive2(String message){
        System.out.println("message2 = " + message);
    }


}

接收到对应范围的消息

MQ的应用场景

异步处理

场景说明:用户注册后,需要发送注册邮件和注册短信,传统的做法有两种 1.串行方式 2.并行方式

  • 串行方式:将注册信息写入数据库后,再发送注册邮件,再发送注册短信。以上三个任务全部完成后才返回客户端。如果邮件、短信不是必须的话,它只是通知而已,那用户就等待了没必要等待的时间。

在这里插入图片描述

  • 并行方式:将注册信息写入数据库后,同时发送注册邮件和注册短信。以上三个任务全部完成后才返回客户端。

在这里插入图片描述

  • 消息队列:引入消息队列后,发送邮件和短信不是必须的业务逻辑,注册成功后就返回客户端,其他消息队列异步处理

在这里插入图片描述

应用解耦

场景:双十一,用户下单后,订单系统需要通知库存系统,传统的做法是订单系统调用库存系统的接口。

在这里插入图片描述

这种做法有一个缺点:

当库存系统出现故障时,订单就会失效。订单系统和库存系统高耦合,引入消息队列

在这里插入图片描述

  • 订单系统:用户下单后,订单系统完成持久化处理,将消息写入消息队列,返回用户下单成功。
  • 库存系统:订阅下单的消息,获取下单的消息,进行库存操作。就算库存系统出现故障,消息队列也能保证消息的可靠投递,不会导致消息丢失。

流量削峰

场景:秒杀活动,一般会因为流量大,导致应用挂掉,为了解决这个问题,一般在应用的前端加入消息队列。

作用:

  1. 可以控制活动人数,超过此一定阀值的订单直接丢弃
  2. 可以缓解短时间的高流量压垮应用

在这里插入图片描述

用户请求先写入消息队列,加入对了的长度超过最大值,则直接抛弃用户请求或跳转到错误页面;秒杀业务根据消息队列中的请求信息,在做后续的处理。

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

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

相关文章

【C初阶】C初阶考试题

选择加编程一、选择题&#xff08;一&#xff09;递归&#xff08;二&#xff09;后置发生死循环&#xff08;三&#xff09;后置运算&#xff08;四&#xff09;操作符运算&#xff08;五&#xff09;全局变量与生命周期&#xff08;六&#xff09;操作符知识&#xff08;七&a…

前端对接微信公众号网页开发流程,前期配置

微信公众号网页开发&#xff0c;其实就是我们开发的h5网页需要放到微信浏览器环境中使用&#xff0c;但是需要对接公众号授权&#xff0c;授权之后可以获取到用户的个人信息&#xff0c;以及可以使用公众号提供的一些API,如&#xff1a;图片上传、图片预览、获取位置信息、微信…

【Java异常】Java异常监控重要手段 --异常链

目录标题前言一、异常链介绍1.1 异常链概述1.2 Java中如何使用异常链二、Throwable1.1 Throwable中哪些API提供存储cause的功能1.2 Throwable中如何获取cause三、项目实战演练示例1:未存储cause示例2:存储cause两层嵌套示例3:存储cause三层嵌套四、总结前言 “异常链”无论是在…

构造题(agc059_b)

https://atcoder.jp/contests/agc059/tasks/ B - Arrange Your Balls Editorial / Time Limit: 2 sec / Memory Limit: 1024 MB Score : 700700 points Problem Statement You have NN balls of colors C_1, C_2, \ldots, C_NC1​,C2​,…,CN​. Here, all colors are rep…

引发C++程序内存错误的常见原因分析与总结

目录 1、概述 2、变量未初始化 2.1、变量未初始化的场景说明 2.2、对0xcccccccc、0xcdcdcdcd和0xfeeefeee等常见异常值的辨识度 3、空指针与野指针 3.1、空指针 3.2、野指针 4、线程栈溢出 5、内存越界 6、内存泄漏 7、堆内存被破坏 8、内存访问违例 8.1、访问64K…

7.Isaac教程--在Python中开发Codelets

在Python中开发Codelets 虽然就性能而言&#xff0c;编写小码的最佳语言是 C&#xff0c;但并非应用程序的所有小码都需要使用相同的语言。 Isaac SDK 还支持 Python codelets&#xff0c;或 pyCodelets&#xff0c;适合那些更熟悉 Python 的人。 本节向您展示如何执行以下操作…

可视化系列讲解:SVG绘制基本图形及如何复用

文章目录一、SVG坐标系二、SVG坐标系单位三、SVG绘制基本图形3.1 矩形3.2 圆形3.3 椭圆3.4 直线3.5 折线3.6 多边型3.7 路径3.8 文字3.9 图片四、SVG元素的组合五、图形元素定义复用和使用定义的复用5.1 defs与use5.2 symbol与use一、SVG坐标系 SVG 使用的坐标系统&#xff08;…

【Python】函数——传递任意数量的实参

传递任意数量的实参和传递任意数量的关键字实参 *args&#xff1a;表示用来接收任意数量的实参&#xff0c;其中&#xff0c;形参*args的星号会让Python创建一个名为args的空元组&#xff0c;并将接收到的任意数量的实参存储在这个元组中。**kwargs&#xff1a;表示用来接收任…

ARX给CAD发送命令的几种方法

本文迁移自本人网易博客&#xff0c;写于2015年11月16日。1、ads_queueexpr( _T("(command\"_POINT\" \"1,1,0\")") );该函数CAD未公开&#xff0c;使用时提前声明下就可以了。可以参考帮助文件中&#xff1a;Tips and Techniques 。2、acDocMan…

嵌入式:人机交互接口设计详解

文章目录键盘和LED的接口原理HD7279A与S3C2410A的连接原理图键盘和LED控制的编程实例LCD显示原理LCD控制器概述嵌入式处理器与LCD的连接S3C2410A的LCD控制器&#xff08;1&#xff09;STN LCD&#xff08;2&#xff09;TFT LCDLCD控制器的框图LCD接口信号STN LCD控制器操作&…

Java IO流 - 转换流的使用详细介绍

文章目录转换流字符输入转换流字符输出转换流转换流 之前我们代码编码和文件编码都是UTF-8, 所以没有出现中文乱码的问题 我们知道代码编码和文件编码的格式如果不一致的话会出现中文乱码的问题 那么如果在开发中, 我们确实会遇到编码不一致的情况如何解决呢? 我们可以使用字符…

【高阶数据结构】手撕红黑树(超详细版本)

&#x1f308;欢迎来到数据结构专栏~~手撕红黑树 (꒪ꇴ꒪(꒪ꇴ꒪ )&#x1f423;,我是Scort目前状态&#xff1a;大三非科班啃C中&#x1f30d;博客主页&#xff1a;张小姐的猫~江湖背景快上车&#x1f698;&#xff0c;握好方向盘跟我有一起打天下嘞&#xff01;送给自己的一句…

JMS规范和AMQP协议

参考资料&#xff1a;《JMS与AMQP简述以及比较》《AMQP协议详解》《MQ消息队列的JMS规范和AMQP协议的区别》《消息队列之JMS和AMQP对比》写在开头&#xff1a;本文为学习后的总结&#xff0c;可能有不到位的地方&#xff0c;错误的地方&#xff0c;欢迎各位指正。一般情况下MQ的…

【数据结构与算法——C语言版】6. 排序算法(3)——插入排序

前言 在本系列的上两篇文章分别介绍了两种O(n2)的排序算法——选择排序和冒泡排序&#xff0c;今天是第三种O(n2)的排序算法&#xff1a;插入排序。 插入排序 核心思想 它的基本思想是将一个记录插入到已经排好序的有序表中&#xff0c;从而产生一个新的、记录数增 1 的有序…

软件测试~自动化测试Seleniums---1

一.什么是自动化测试 1.自动化测试介绍 自动化测试指软件测试的自动化&#xff0c;在预设状态下运行应用程序或者系统&#xff0c;预设条件包括正常和异常&#xff0c;最后评估运行结果。将人为驱动的测试行为转化为机器执行的过程。 将测试人员双手解放&#xff0c;将部分测…

机器视觉(十):印刷体字符识别

目录&#xff1a; 机器视觉&#xff08;一&#xff09;&#xff1a;概述 机器视觉&#xff08;二&#xff09;&#xff1a;机器视觉硬件技术 机器视觉&#xff08;三&#xff09;&#xff1a;摄像机标定技术 机器视觉&#xff08;四&#xff09;&#xff1a;空域图像增强 …

Unreal模块创建流程

可以把开发中通用的功能封装成模块,以在不同项目之间复用,这里记录一下创建模块的步骤:在工程的Source文件夹中新建文件夹,命名为模块名称TestCustomModule:如果要区分模块内脚本的公私有权限,则在模块文件夹内创建Public和Private文件夹,这里我没有区分,就不创建了:在模块文件…

Js如何实现一个累加向上漂浮动画

前言 在不久之前,看到一个比较有意思的小程序,就是静神木鱼,可以实现在线敲木鱼,自动敲木鱼,手盘佛珠,静心颂钵的 整个小程序功能比较小巧,大道至简,曾风靡过一阵的,无论在App应用市场上,还是小程序里,一些开发者都赚得盆满钵满,用于缓解当代年轻人的一个焦虑,佛系解压,算是一…

Kubernetes:通过轻量化工具 kubespy 实时观察YAML资源变更

写在前面 分享一个小工具 kubespy 给小伙伴博文内容涉及&#xff1a; 工具的简单介绍下载安装以 kubectl 插件方式使用 Demo 理解不足小伙伴帮忙指正 我所渴求的&#xff0c;無非是將心中脫穎語出的本性付諸生活&#xff0c;為何竟如此艱難呢 ------赫尔曼黑塞《德米安》 简单介…

详解二分查找的两种写法以及二分查找的六种变形

目录 一、二分查找的两种写法 1.1 - 第一种写法&#xff08;左闭右闭&#xff09; 1.2 - 第二种写法&#xff08;左闭右开&#xff09; 二、二分查找的六种变形 2.1 - 查找第一个 target 的元素位置 2.2 - 查找第一个 > target 的元素位置 2.3 - 查找第一个 > ta…