[RabbitMQ] Spring Boot整合RabbitMQ

🌸个人主页:https://blog.csdn.net/2301_80050796?spm=1000.2115.3001.5343
🏵️热门专栏:
🧊 Java基本语法(97平均质量分)https://blog.csdn.net/2301_80050796/category_12615970.html?spm=1001.2014.3001.5482
🍕 Collection与数据结构 (92平均质量分)https://blog.csdn.net/2301_80050796/category_12621348.html?spm=1001.2014.3001.5482
🧀线程与网络(96平均质量分) https://blog.csdn.net/2301_80050796/category_12643370.html?spm=1001.2014.3001.5482
🍭MySql数据库(93平均质量分)https://blog.csdn.net/2301_80050796/category_12629890.html?spm=1001.2014.3001.5482
🍬算法(97平均质量分)https://blog.csdn.net/2301_80050796/category_12676091.html?spm=1001.2014.3001.5482
🍃 Spring(97平均质量分)https://blog.csdn.net/2301_80050796/category_12724152.html?spm=1001.2014.3001.5482
🎃Redis(97平均质量分)https://blog.csdn.net/2301_80050796/category_12777129.html?spm=1001.2014.3001.5482
🐰RabbitMQ(97平均质量分) https://blog.csdn.net/2301_80050796/category_12792900.html?spm=1001.2014.3001.5482
感谢点赞与关注~~~
在这里插入图片描述

目录

  • 1. 工作队列模式
  • 2. Publish/Subscribe(发布订阅模式)
  • 3. Routing(路由模式)
  • 4. Topics(通配符模式)
  • 5. 实际案例
    • 5.1 创建项目
    • 5.2 订单系统(生产者)
    • 5.3 物流系统(消费者)

RabbitMQ开发,Spring也提供了一些便利.下面我们就来学习如何使用Spring操作RabbitMQ.

1. 工作队列模式

步骤:

  1. 引入依赖
  2. 编写yml设置,基本信息配置.
  3. 编写生产者代码.
  4. 编写消费者代码.(定义监听类,使用@RabbitListener注解完成队列监听).
  5. 观察运行结果.
  • 引入依赖
    在我们创建Spring项目的依赖的时候,我们可以引入Spring For RabbitMQ依赖.
    在这里插入图片描述
    也可以手动导入xml依赖:
<dependency>
    <groupId>org.springframework.amqp</groupId>
    <artifactId>spring-rabbit-test</artifactId>
    <scope>test</scope>
</dependency>
  • 添加配置
    我们需要在yml文件中配置服务器的IP地址,RabbitMQ的服务端口号(默认5672),用户名,密码,以及我们要使用的虚拟机.
spring:
  application:
   name: rabbitmq-spring
  rabbitmq:
    host: 39.105.137.64
    port: 5672
    username: jiangruijia
    password: qwe123524
    virtual-host: /
  • 编写生产者代码
    为了方便测试,我们通过接口来发送信息.
    首先我们需要在Constant类中定义队列的名称.
public static final String WORK_QUEUE = "work_queue";

之后在config中声明队列.

@Configuration
public class RabbitMQConfig {
    @Bean
    public Queue workQueue(){
        return QueueBuilder.durable(Constant.WORK_QUEUE).build();//指定队列的名称
    }
}

durable中写入的是队列的名称,最后方法返回的是创建好的队列.

@RestController
@RequestMapping("/producer")
public class ProducerController {
    @Autowired
    private RabbitTemplate rabbitTemplate;
    @RequestMapping("/work")
    public String work(){
        rabbitTemplate.convertAndSend("",Constant.WORK_QUEUE,"发送消息");//指定发送消息的交换机和队列,以及发送的消息
        return "发送成功";
    }
}

我们在编写生产者代码的时候,我们需要注入RabbitTemplate对象(类似于Redis中的StringRedisTemplate对象),使用这个对象来操作RabbitMQ.之后我们需要在一个方法中发送信息,convertAndSend创建了生产者并向指定的队列中发送了信息,convertAndSend需要指定交换机,队列名称和需要发送的消息.
我们来运行代码,并访问指定的端口,从RabbitMQ的管理界面中查看消息.
在这里插入图片描述

在这里插入图片描述
我们可以从队列中获取到预期的消息:
在这里插入图片描述

  • 编写消费者代码
@Component
public class WorkListener {//工作模式中,消费者有两个
    @RabbitListener(queues = Constant.WORK_QUEUE)//监听指定的队列
    public void workListener1(Message message){
        System.out.println("workListener1收到消息:"+message);
    }
    @RabbitListener(queues = Constant.WORK_QUEUE)
    public void workListener2(Message message){
        System.out.println("workListener2收到消息:"+message);
    }
}

在创建消费者的时候,我们需要使用@Component把消费者类注入到Spring中,之后,我们要在对应的方法上添加@RabbitListener,指定该方法为监听者,在后面的queues属性中指定需要监听的队列.
运行上述代码:在运行之后,我们发现消息队列中的信息减少了.而且在控制台中也打印出了收到的对应的消息.
在这里插入图片描述
在这里插入图片描述
@RabbitListener修饰的方法的参数中,不仅仅可以指定Message类型的参数,还可以指定一下常见的参数:

  1. String: 返回消息的内容
  2. Message: 注意是org.springframework.amqp.core.Message包中的Message,在导包的时候不要导错.返回的是原始的消息体以及消息的属性,如消息ID,内容,队列.
  3. Channel: RabbitMQ中的通道消息对象,可以用于进行更高级的操作,比如手动确认.

2. Publish/Subscribe(发布订阅模式)

在发布/订阅模式中,多了一个交换机的角色.exchange常见的有三种类型,我们在前面介绍过,发别是:fanout广播模式,将消息交给所有绑定交换机的队列.direct定向模式,把消息交给符合指定RoutingKey的队列.topic通配符模式,把消息交给符合routing pattern(路由模式)的队列,只不过这里的RoutingKey中含有通配符.而定向模式中的RoutingKey是写死的.

  • 编写生产者代码
    和简单模式,工作队列模式最大的区别就是需要创建交换机,并绑定交换机和队列.
    首先我们声明队列,交换机的名称.
public static final String FANOUT_QUEUE1 = "fanout_queue1";
public static final String FANOUT_QUEUE2 = "fanout_queue2";
public static final String FANOUT_EXCHANGE = "fanout_exchange";

之后我们需要在声明交换机和队列,并绑定交换机和队列.之后使用@Bean注解进行注入.

@Bean
public Queue fanoutQueue1(){
    return QueueBuilder.durable(Constant.FANOUT_QUEUE1).build();
}
@Bean
public Queue fanoutQueue2(){
    return QueueBuilder.durable(Constant.FANOUT_QUEUE2).build();
}
@Bean
public FanoutExchange fanoutExchange(){
    return ExchangeBuilder.fanoutExchange(Constant.FANOUT_EXCHANGE).durable(true).build();
}

在创建交换机的时候,我们需要使用 ExchangeBuilder.fanoutExchange方法来指定交换机的名字,之后使用durable指定交换机为持久化.注意在返回交换机的时候,必须返回的是具体类型的交换机.队列的创建方法和前面的创建方法相同.
之后我们对交换机和队列进行绑定.

@Bean
public Binding binding1(@Qualifier("fanoutExchange") FanoutExchange exchange, @Qualifier("fanoutQueue1") Queue queue){
    return BindingBuilder.bind(queue).to(exchange);
}
@Bean
public Binding binging2(@Qualifier("fanoutExchange") FanoutExchange exchange,@Qualifier("fanoutQueue2") Queue queue){
    return BindingBuilder.bind(queue).to(exchange);
}

在绑定的时候,我们需要使用@Qualifier注解进行注入,注意注入的交换机类型必须和Spring容器中的交换机类型一致,都是fanout类型的交换机.bind方法中写入的是需要绑定的队列,to中写入的是需要绑定的交换机.
之后我们使用接口发送消息.

@RequestMapping("/fanout")
public String fanout(){
    rabbitTemplate.convertAndSend(Constant.FANOUT_EXCHANGE,"","fanout交换机发送消息");//指定发送的交换机即可,由于是广播模式,RoutingKey不需要指定
    return "发送成功";
}
  • 编写消费者代码
    定义监听类,处理收到的消息即可.
@Component
public class FanoutListener {
    @RabbitListener(queues = Constant.FANOUT_QUEUE1)
    public void ListenerQueue1(String message){
        System.out.println("queue1收到消息:"+message);
    }
    @RabbitListener(queues = Constant.FANOUT_QUEUE2)
    public void ListenerQueue2(String message){
        System.out.println("queue2收到消息:"+message);
    }
}

运行项目,之后访问Controller对应的接口.
在这里插入图片描述
在这里插入图片描述
rabbbitMQ的管理界面,消息条数发生了波动,控制台成功收到了生产者发送的消息.

3. Routing(路由模式)

交换机类型为direct类型的时候,消息会把消息交给符合指定RoutingKey的队列.队列和交换机的绑定,不是任意绑定了,而是需要指定一个RoutingKey.交换机也不再把消息交给每一个绑定的key,而是根据消息的RoutingKey进行判断,只有队列的RoutingKey和消息的RoutingKey完全一致,才会收到消息.

  • 编写生产者代码
    指定队列和交换机的名称
public static final String DIRECT_EXCHANGE = "direct_exchange";
public static final String DIRECT_QUEUE1 = "direct_queue1";
public static final String DIREct_QUEUE2 = "direct_queue2";

接下来声明交换机和队列

@Bean
public Queue directQueue1(){
    return QueueBuilder.durable(Constant.DIRECT_QUEUE1).build();
}
@Bean
public Queue directQueue2(){
    return QueueBuilder.durable(Constant.DIREct_QUEUE2).build();
}
@Bean
public DirectExchange directExchange(){
    return ExchangeBuilder.directExchange(Constant.DIRECT_EXCHANGE).durable(true).build();
}

接下来绑定队列和交换机,指定绑定时候的BindingKey.

@Bean
public Binding directBinding1(@Qualifier("directExchange") DirectExchange exchange,@Qualifier("directQueue1") Queue queue){
    return BindingBuilder.bind(queue).to(exchange).with("orange");
}
@Bean
public Binding directBinding2(@Qualifier("directExchange") DirectExchange exchange,@Qualifier("directQueue2") Queue queue){
    return BindingBuilder.bind(queue).to(exchange).with("green");
}
@Bean
public Binding directBinding3(@Qualifier("directExchange") DirectExchange exchange,@Qualifier("directQueue2") Queue queue){
    return BindingBuilder.bind(queue).to(exchange).with("red");
}

相比广播模式,多了with指定了绑定时候的BindingKey.
使用接口发送消息.

@RequestMapping("/direct")
public String direct(String routingKey){
    rabbitTemplate.convertAndSend(Constant.DIRECT_EXCHANGE,routingKey,"direct生产者发送消息");
    return "发送成功";
}

与前面广播不同的是,在发送消息的时候,需要在参数中指定RoutingKey,在给交换机发送消息的时候,需要把传入的RoutingKey传入convertAndSend中.

  • 编写消费者代码
    消费者的编写方式和前面几种方式都差不多,都是在指定的方法上添加@RabbitListener注解,在注解中指定需要监听的队列.
@Component
public class DirectListener {
    @RabbitListener(queues = Constant.DIRECT_QUEUE1)
    public void ListenerQueue1(String message){
        System.out.println("监听队列1:"+message);
    }
    @RabbitListener(queues = Constant.DIREct_QUEUE2)
    public void ListenerQueue2(String message){
        System.out.println("监听队列2:"+message);
    }
}

运行项目并访问指定接口.
http://127.0.0.1:8080/producer/direct?routingKey=green
在这里插入图片描述
http://127.0.0.1:8080/producer/direct?routingKey=red
在这里插入图片描述
http://127.0.0.1:8080/producer/direct?routingKey=orange
在这里插入图片描述
在这里插入图片描述

4. Topics(通配符模式)

Topic和Routing模式的区别是:

  1. topics模式使用的交换机类型为topic(Routing模式使用的交换机类型为direct)
  2. topic类型的交换机在匹配规则上进行了扩展,BindingKey支持通配符匹配.
  • 编写生产者代码
    首先还是指定队列和交换机的名称
public static final String TOPICS_QUEUE1 = "topics_queue1";
public static final String TOPICS_QUEUE2 = "topics_queue2";
public static final String TOPICS_EXCHANGE = "topics_exchange";

之后声明交换机和队列.

@Bean
public Queue topicsQueue1(){
    return QueueBuilder.durable(Constant.TOPICS_QUEUE1).build();
}
@Bean
public Queue topicsQueue2(){
    return QueueBuilder.durable(Constant.TOPICS_QUEUE2).build();
}
@Bean
public TopicExchange topicExchange(){
    return ExchangeBuilder.topicExchange(Constant.TOPICS_EXCHANGE).durable(true).build();
}

绑定交换机和队列,并指定BindingKey

@Bean
public Binding topicsBinding1(@Qualifier("topicsExchange") TopicExchange exchange, @Qualifier("topicsQueue1") Queue queue){
    return BindingBuilder.bind(queue).to(exchange).with("#.error");
}
@Bean
public Binding topicsBinding2(@Qualifier("topicsExchange") TopicExchange exchange,@Qualifier("topicsQueue2") Queue queue){
    return BindingBuilder.bind(queue).to(exchange).with("#.info");
}

之后我们使用接口来接收信息.

@RequestMapping("/topics")
public String topics(String routingKey){
    rabbitTemplate.convertAndSend(Constant.TOPICS_EXCHANGE,routingKey,"topics生产者发送消息");
    return "发送成功";
}
  • 编写消费者代码
@Component
public class TopicsListener {
    @RabbitListener(queues = Constant.TOPICS_QUEUE1)
    public void topicsListener1(String message){
        System.out.println("topics队列1接收到消息"+message);
    }
    @RabbitListener(queues = Constant.TOPICS_QUEUE2)
    public void topicsListener2(String message){
        System.out.println("topics队列2接收到消息"+message);
    }
}

运行项目,访问接口,传递指定参数,观察结果
http://127.0.0.1:8080/producer/topics?routingKey=404.error
在这里插入图片描述
http://127.0.0.1:8080/producer/topics?routingKey=200.info
在这里插入图片描述
在这里插入图片描述

5. 实际案例

作为一个消息队列,RabbitMQ也可以用作应用程序之间的通信.上述代码和生产者和消费者代码放在不同的项目模块中即可完成不同的应用程序通信.
比如我们需要实现下面的功能:
用户下单成功之后,通知物流系统进行发货.
在这里插入图片描述
这里我们只做应用通信,我们不对业务逻辑做具体实现.

5.1 创建项目

我们在创建项目的时候,把两个项目放在同一个空项目中.

  1. 创建一个空项目
    在这里插入图片描述
  2. 之后在这个项目中创建一个模块
    在这里插入图片描述
  3. 后续流程和创建SpringBoot项目一样.
    在这里插入图片描述
    在模块创建的时候,我们在每个项目中都会引入如下的依赖:
    在这里插入图片描述
    最终的项目结构如下:
    在这里插入图片描述
    我们在创建项目之后有可能无法加载项目为Maven项目,我们可以在指定的项目的pom文件中右键—>添加为Maven项目即可.

5.2 订单系统(生产者)

  1. 完善配置信息
spring:
  application:
   name: logistics-service
  rabbitmq:
    host: 39.105.137.64
    port: 5672
    username: jiangruijia
    password: qwe123524
    virtual-host: /
  1. 声明队列
@Configuration
public class RabbitMQConfig {
    @Bean
    public Queue workQueue(){
        return QueueBuilder.durable("order.create").build();
    }
}
  1. 编写下单接口,下单成功之后,发送订单消息到队列.
@RestController
@RequestMapping("/order")
public class OrderController {
    @Autowired
    private RabbitTemplate rabbitTemplate;
    @RequestMapping("/createOrder")
    public String createOrder(){
        String order = UUID.randomUUID().toString();
        rabbitTemplate.convertAndSend("","order.create","下单成功:"+order);
        return "下单成功";
    }
}
  1. 启动服务,访问对应接口,观察结果

    消息条数出现了波动.
    在这里插入图片描述
    从队列中查看消息:
    在这里插入图片描述

5.3 物流系统(消费者)

  1. 完善配置信息
    8080端口号已经订单系统被占领,所以我们需要更改物流系统的端口号为9090.
spring:
  application:
    name: logistics-service
  rabbitmq:
    host: 39.105.137.64
    port: 5672
    username: jiangruijia
    password: qwe123524
    virtual-host: /
server:
  port: 9090
  1. 消费者监听队列
@Component
public class OrderControllerListener {
    @RabbitListener(queues = "order.create")
    public void ListenerQueue(String message){
        System.out.println("接收到订单:"+message);
        //此处业务逻辑省略
    }
}

启动服务,观察结果:
在这里插入图片描述
在这里插入图片描述
我们看到了消费者成功接收到了订单id.

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

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

相关文章

Scrapy 爬虫的大模型支持

使用 Scrapy 时&#xff0c;你可以轻松使用大型语言模型 (LLM) 来自动化或增强你的 Web 解析。 有多种使用 LLM 来帮助进行 Web 抓取的方法。在本指南中&#xff0c;我们将在每个页面上调用一个 LLM&#xff0c;从中抽取我们定义的一组属性&#xff0c;而无需编写任何选择器或…

C++和OpenGL实现3D游戏编程【连载13】——多重纹理混合详解

🔥C++和OpenGL实现3D游戏编程【目录】 1、本节要实现的内容 前面说过纹理贴图能够大幅提升游戏画面质量,但纹理贴图是没有叠加的。在一些游戏场景中,要求将非常不同的多个纹理(如泥泞的褐色地面、绿草植密布的地面、碎石遍布的地面)叠加(混合)起来显示,实现纹理间能够…

多区域OSPF路由协议

前言 之前也有过关于OSPF路由协议的博客&#xff0c;但都不是很满意&#xff0c;不是很完整。现在也是听老师讲解完OSPF路由协议&#xff0c;感触良多&#xff0c;所以这里重新整理一遍。这次应该是会满意的 一些相关概念 链路状态 链路指路由器上的一个接口&#xff0c;链路状…

【社保通-注册安全分析报告-滑动验证加载不正常导致安全隐患】

前言 由于网站注册入口容易被黑客攻击&#xff0c;存在如下安全问题&#xff1a; 暴力破解密码&#xff0c;造成用户信息泄露短信盗刷的安全问题&#xff0c;影响业务及导致用户投诉带来经济损失&#xff0c;尤其是后付费客户&#xff0c;风险巨大&#xff0c;造成亏损无底洞…

新手教学系列——爬虫异步并发注意事项

引言 爬虫是网络数据采集中不可或缺的工具,很多程序员在入门时会遇到这样的问题:为什么我的爬虫这么慢?尤其在面对大量数据时,单线程爬虫的速度可能让人捶胸顿足。随着爬虫规模的增大,异步并发成为了提高爬取效率的关键。然而,异步并发并不像表面看起来那么简单,如果没…

初识Linux · 进程替换

目录 前言&#xff1a; 1 直接看代码和现象 2 解释原理 3 将代码改成多进程版本 4 认识所有函数并使用 前言&#xff1a; 由前面的章节学习&#xff0c;我们已经了解了进程状态&#xff0c;进程终止以及进程等待&#xff0c;今天&#xff0c;我们学习进程替换。进程替换我…

Python:import语句的使用(详细解析)(一)

相关阅读 Pythonhttps://blog.csdn.net/weixin_45791458/category_12403403.html?spm1001.2014.3001.5482 import语句是Python中一个很重要的机制&#xff0c;允许在一个文件中访问另一个文件的函数、类、变量等&#xff0c;本文就将进行详细介绍。 在具体谈论import语句前&a…

hbuilderx+uniapp+Android宠物用品商城领养服务系统的设计与实现 微信小程序沙箱支付

目录 项目介绍支持以下技术栈&#xff1a;具体实现截图HBuilderXuniappmysql数据库与主流编程语言java类核心代码部分展示登录的业务流程的顺序是&#xff1a;数据库设计性能分析操作可行性技术可行性系统安全性数据完整性软件测试详细视频演示源码获取方式 项目介绍 顾客 领养…

设计模式、系统设计 record part02

软件设计模式&#xff1a; 1.应对重复发生的问题 2.解决方案 3.可以反复使用 1.本质是面向对象 2.优点很多 1.创建型-创建和使用分离 2.结构型-组合 3.行为型-协作 571123种模式 UML-统一建模语言-Unified Modeling Language 1.可视化&#xff0c;图形化 2.各种图&#xff08;9…

PostgreSQL 任意命令执行漏洞(CVE-2019-9193)

记一次授权攻击通过PostgreSql弱口令拿到服务器权限的事件。 使用靶机复现攻击过程。 过程 在信息收集过程中&#xff0c;获取到在公网服务器上开启了5432端口&#xff0c;尝试进行暴破&#xff0c;获取到数据库名为默认postgres&#xff0c;密码为1 随后连接进PostgreSql …

【CSS in Depth 2 精译_043】6.5 CSS 中的粘性定位技术 + 本章小结

当前内容所在位置&#xff08;可进入专栏查看其他译好的章节内容&#xff09; 第一章 层叠、优先级与继承&#xff08;已完结&#xff09;第二章 相对单位&#xff08;已完结&#xff09;第三章 文档流与盒模型&#xff08;已完结&#xff09;第四章 Flexbox 布局&#xff08;已…

项目定位与服务器(SERVER)模块划分

目录 定位 HTTP协议以及HTTP服务器 高并发服务器 单Reactor单线程 单Reactor多线程 多Reactor多线程 模块划分 SERVER模块划分 Buffer 模块 Socket模块 Channel 模块 Connection模块 Acceptor模块 TimerQueue模块 Poller模块 EventLoop模块 TcpServer模块 SE…

HTML5+CSS+JavaScript剪子石头布游戏

HTML5CSSJavaScript剪子石头布游戏 用HTML5CSSJavaScript剪子石头布游戏实现剪子石头布游戏&#xff0c;游戏有成绩计数&#xff0c;人、机输赢情况&#xff0c;及平局情况。 ✂代表剪刀&#xff0c;▉代表石头&#xff0c;▓ 代表布&#xff0c;给出人机双方的出拳情况 游戏…

【LeetCode每日一题】——17.电话号码的字母组合

文章目录 一【题目类别】二【题目难度】三【题目编号】四【题目描述】五【题目示例】六【题目提示】七【解题思路】八【时间频度】九【代码实现】十【提交结果】 一【题目类别】 回溯 二【题目难度】 中等 三【题目编号】 17.电话号码的字母组合 四【题目描述】 给定一个…

看480p、720p、1080p、2k、4k、视频一般需要多大带宽呢?

看视频都喜欢看高清&#xff0c;那么一般来说看电影不卡顿需要多大带宽呢&#xff1f; 以4K为例&#xff0c;这里引用一位网友的回答&#xff1a;“视频分辨率4092*2160&#xff0c;每个像素用红蓝绿三个256色(8bit)的数据表示&#xff0c;视频帧数为60fps&#xff0c;那么一秒…

向日葵软件安装失败

一开始点击普通下载&#xff0c;下载完毕后&#xff0c;安装了好几次也没安装成功。 查找解决方法后 在控制面板-程序和功能&#xff0c;寻找已安装 的向日葵 手动卸载已安装但是又没成功的向日葵 重新点击普通下载&#xff0c;下载完安装还是失败。 于是改为安全下载&…

k8s的学习和使用

为什么用k8s&#xff0c;不用docker&#xff1f; k8s更适合复杂的微服务架构和大规模的容器应用。 Pods(Pod) Pod是k8s最小可部署单元&#xff0c;他包含一个或多个相关容器。这些容器共享网络命名空间和存储卷&#xff0c;他们通常协同工作来构成一个应用程序。 Serv…

C(十)for循环 --- 黑神话情景

前言&#xff1a; "踏过三界宝刹&#xff0c;阅过四洲繁华。笑过五蕴痴缠&#xff0c;舍过六根牵挂。怕什么欲念不休&#xff0c;怕什么浪迹天涯。步履不停&#xff0c;便是得救之法。" 国际惯例&#xff0c;开篇先喝碗鸡汤。 今天&#xff0c;杰哥写的 for 循环相…

CSS 实现楼梯与小球动画

CSS 实现楼梯与小球动画 效果展示 CSS 知识点 CSS动画使用transform属性使用 页面整体布局 <div class"window"><div class"stair"><span style"--i: 1"></span><span style"--i: 2"></span>…