【RabbitMQ】六种模式与SpringBoot整合
添加rabbitmq的依赖
- <dependency>
- <groupId>org.springframework.boot</groupId>
- <artifactId>spring-boot-starter-amqp</artifactId>
- </dependency>
在配置文件中添加必要的配置信息
- spring.rabbitmq.host=192.168.0.86
- spring.rabbitmq.port=5672
- spring.rabbitmq.username=admin
- spring.rabbitmq.password=123456
好了,基本的配置就已经配置完毕了
rabbitmq有六种模式
我们逐个来看springboot是怎么实现的呢
1.hello world
P代表生产者,C代表消费者,红色代码消息队列。P将消息发送到消息队列,C对消息进行处理。
我们先创建一个队列
- @Bean
- public Queue Queue() {
- return new Queue("hello");
- }
然后我再创建一个生产者

- @Controller
- public class HelloSender {
- @Autowired
- private AmqpTemplate rabbitTemplate;
- public void send() {
- String context = "hello " + new Date();
- System.out.println("Sender : " + context);
- this.rabbitTemplate.convertAndSend("hello", context);
- }
- }

再创建一个消费者

- @Component
- @RabbitListener(queues = "hello")
- public class HelloReceiver {
- @RabbitHandler
- public void process(String hello) {
- System.out.println("Receiver : " + hello);
- }
- }

再写一个测试用例看看

- @RunWith(SpringRunner.class)
- @SpringBootTest
- public class RabbitmqApplicationTests {
- @Autowired
- private HelloSender helloSender;
- @Test
- public void hello() throws Exception {
- helloSender.send();
- }
- }

成功!
2.工作模式(竞争)
一个消息产生者,多个消息的消费者。竞争抢消息
我们先创建一个队列
- @Bean
- public Queue Queue2() {
- return new Queue("neo");
- }
再创建一个消息生产者

- @Controller
- public class NeoSender {
- @Autowired
- private AmqpTemplate rabbitTemplate;
- public void send(int i) {
- String context = "spirng boot neo queue"+" ****** "+i;
- System.out.println("Sender1 : " + context);
- this.rabbitTemplate.convertAndSend("neo", context);
- }
- }

再创建两个消息的消费者

- 1 @Component
- 2 @RabbitListener(queues = "neo")
- 3 public class NeoReceiver1 {
- 4 @RabbitHandler
- 5 public void process(String neo) {
- 6 System.out.println("Receiver 1: " + neo);
- 7 }
- 8 }
- 9
- 10
- 11
- 12 @Component
- 13 @RabbitListener(queues = "neo")
- 14 public class NeoReceiver2 {
- 15 @RabbitHandler
- 16 public void process(String neo) {
- 17 System.out.println("Receiver 2: " + neo);
- 18 }
- 19
- 20 }

我们写一个测试用例

- @Test
- public void oneToMany() throws Exception {
- for (int i=0;i<100;i++){
- // Thread.sleep(10);
- neoSender.send(i);
- }
- }

运行
可以看到消息均匀的被两个消费者消费了。
通过这个例子我们可以看做高并发情况下的消息产生和消费,这会产生一个消息丢失的问题。万一客户端在处理消息的时候挂了,那这条消息就相当于被浪费了,针对这种情况,rabbitmq推出了消息ack机制,熟悉tcp三次握手的一定不会陌生。
我们看看springboot是实现ack的
很简单,在我们的配置类中,配置一个新的消费者,将原先的消费者先都去掉:

- @Bean
- public SimpleMessageListenerContainer messageContainer() {
- SimpleMessageListenerContainer container = new SimpleMessageListenerContainer(connectionFactory());
- container.setQueues(Queue());
- container.setExposeListenerChannel(true);
- container.setMaxConcurrentConsumers(1);
- container.setConcurrentConsumers(1);
- container.setAcknowledgeMode(AcknowledgeMode.MANUAL);//消息确认后才能删除
- container.setPrefetchCount(5);//每次处理5条消息
- container.setMessageListener(new ChannelAwareMessageListener() {
- public void onMessage(Message message, com.rabbitmq.client.Channel channel) throws Exception {
- byte[] body = message.getBody();
- System.out.println("消费端接收到消息 : " + new String(body));
- channel.basicAck(message.getMessageProperties().getDeliveryTag(), false);
- }
- });
- return container;
- }

但这里会有个问题,test模式下消息发送完毕系统就会直接shutdown,所以只能消费部分消息,不过等真正启动项目,这个问题就不存在了。
3.发布订阅模式
生产者将消息不是直接发送到队列,而是发送到X交换机,然后由交换机发送给两个队列,两个消费者各自监听一个队列,来消费消息。
这种方式实现同一个消息被多个消费者消费。工作模式是同一个消息只能有一个消费者。
我们新建三个队列

- @Bean
- public Queue AMessage() {
- return new Queue("fanout.A");
- }
- @Bean
- public Queue BMessage() {
- return new Queue("fanout.B");
- }
- @Bean
- public Queue CMessage() {
- return new Queue("fanout.C");
- }

再新建一个交换机
- @Bean
- FanoutExchange fanoutExchange() {
- return new FanoutExchange("fanoutExchange");
- }
再把这些队列绑定到交换机上去

- @Bean
- Binding bindingExchangeA(Queue AMessage, FanoutExchange fanoutExchange) {
- return BindingBuilder.bind(AMessage).to(fanoutExchange);
- }
- @Bean
- Binding bindingExchangeB(Queue BMessage, FanoutExchange fanoutExchange) {
- return BindingBuilder.bind(BMessage).to(fanoutExchange);
- }
- @Bean
- Binding bindingExchangeC(Queue CMessage, FanoutExchange fanoutExchange) {
- return BindingBuilder.bind(CMessage).to(fanoutExchange);
- }

基本的配置完成后,再新建一个消息生产者

- @Component
- public class FanoutSender {
- @Autowired
- private AmqpTemplate rabbitTemplate;
- public void send() {
- String context = "hi, fanout msg ";
- System.out.println("Sender : " + context);
- this.rabbitTemplate.convertAndSend("fanoutExchange","", context);
- }
- }

同样的,我们再新建三个消息消费者

- 1 @Component
- 2 @RabbitListener(queues = "fanout.A")
- 3 public class FanoutReceiveA {
- 4
- 5 @RabbitHandler
- 6 public void process(String message) {
- 7 System.out.println("fanout Receiver A : " + message);
- 8 }
- 9 }
- 10
- 11 @Component
- 12 @RabbitListener(queues = "fanout.B")
- 13 public class FanoutReceiverB {
- 14 @RabbitHandler
- 15 public void process(String message) {
- 16 System.out.println("fanout Receiver B: " + message);
- 17 }
- 18 }
- 19
- 20 @Component
- 21 @RabbitListener(queues = "fanout.C")
- 22 public class FanoutReceiverC {
- 23 @RabbitHandler
- 24 public void process(String message) {
- 25 System.out.println("fanout Receiver C: " + message);
- 26 }
- 27 }

三个消费者分别监听3个队列的内容
新建一个测试用例:

- @RunWith(SpringRunner.class)
- @SpringBootTest
- public class FanoutTest {
- @Autowired
- private FanoutSender fanoutSender;
- @Test
- public void setFanoutSender(){
- fanoutSender.send();
- }
- }

三个队列都接受到了消息
4:路由模式
需要将一个队列绑定到交换机上,要求该消息与一个特定的路由键完全匹配,这是一个完整的匹配。
5.主题模式
发送端不只按固定的routing key发送消息,而是按字符串匹配发送,接收端同样如此
符号#匹配一个或多个词,符号*匹配不多不少一个词。
4/5两者模式很相似,我们放在一起演示
新建两个队列

- final static String message = "topic.A";
- final static String messages = "topic.B";
- @Bean
- public Queue queueMessage() {
- return new Queue(TopicRabbitConfig.message);
- }
- @Bean
- public Queue queueMessages() {
- return new Queue(TopicRabbitConfig.messages);
- }

新建一个交换机
- @Bean
- TopicExchange exchange() {
- return new TopicExchange("topicExchange");
- }
绑定队列到交换机上,路由模式,需要完整匹配topic.message,才能接受
- @Bean
- Binding bindingExchangeMessage(Queue queueMessage, TopicExchange exchange) {
- return BindingBuilder.bind(queueMessage).to(exchange).with("topic.message");
- }
topic模式,前缀匹配到topic.即可接受
- @Bean
- Binding bindingExchangeMessages(Queue queueMessages, TopicExchange exchange) {
- return BindingBuilder.bind(queueMessages).to(exchange).with("topic.#");
- }
我们新建三个消息生产者

- @Component
- public class TopicSend {
- @Autowired
- private AmqpTemplate rabbitTemplate;
- public void send() {
- String context = "hi, i am message all";
- System.out.println("Sender : " + context);
- this.rabbitTemplate.convertAndSend("topicExchange", "topic.1", context);
- }
- public void send1() {
- String context = "hi, i am message 1";
- System.out.println("Sender : " + context);
- this.rabbitTemplate.convertAndSend("topicExchange", "topic.message", context);
- }
- public void send2() {
- String context = "hi, i am messages 2";
- System.out.println("Sender : " + context);
- this.rabbitTemplate.convertAndSend("topicExchange", "topic.messages", context);
- }
- }

send的key是topic.1 send1的key是topic.message,send2的key是topic.messages
所以理论上send会被两个队列消费,1.2都应该只有一个队列消费
我们再新建两个消费者

- @Component
- @RabbitListener(queues = "topic.A")
- public class TopicReceiver {
- @RabbitHandler
- public void process(String message) {
- System.out.println("Topic Receiver1 : " + message);
- }
- }
- @Component
- @RabbitListener(queues = "topic.B")
- public class TopicReceiver2 {
- @RabbitHandler
- public void process(String message) {
- System.out.println("Topic Receiver2 : " + message);
- }
- }

写三个测试用例

- @RunWith(SpringRunner.class)
- @SpringBootTest
- public class TopicTest {
- @Autowired
- private TopicSend sender;
- @Test
- public void topic() throws Exception {
- sender.send();
- }
- @Test
- public void topic1() throws Exception {
- sender.send1();
- }
- @Test
- public void topic2() throws Exception {
- sender.send2();
- }
- }

send的运行结果
send1的运行结果
send2的运行结果
结果符合预期。
转自:https://www.cnblogs.com/xmzJava/p/8036591.html
【RabbitMQ】六种模式与SpringBoot整合的更多相关文章
- 一篇学习完rabbitmq基础知识,springboot整合rabbitmq
一 rabbitmq 介绍 MQ全称为Message Queue,即消息队列, RabbitMQ是由erlang语言开发,基于AMQP(Advanced MessageQueue 高级消息队列协议 ...
- 初窥RabbitMQ消息中间及SpringBoot整合
一:RabbitMQ简介 RabbitMQ介绍 RabbitMQ 即一个消息队列,主要是用来实现应用程序的异步和解耦,同时也能起到消息缓冲,消息分发的作用. 消息中间件最主要的作用是解耦,中间件最标准 ...
- RabbitMQ基础组件和SpringBoot整合RabbitMQ简单示例
交换器(Exchange) 交换器就像路由器,我们先是把消息发到交换器,然后交换器再根据绑定键(binding key)和生产者发送消息时的路由键routingKey, 按照交换类型Exchange ...
- SpringBoot整合RabbitMQ实现六种工作模式
RabbitMQ主要有六种种工作模式,本文整合SpringBoot分别介绍工作模式的实现. 前提概念 生产者 消息生产者或者发送者,使用P表示: 队列 消息从生产端发送到消费端,一定要通过队列转发,使 ...
- RabbitMQ与SpringBoot整合
RabbitMQ SpringBoot 一.RabbitMQ的介绍 二.Direct模式 三.Topic转发模式 四.Fanout Exchange形式 原文地址: https://www.cnb ...
- springboot学习笔记-6 springboot整合RabbitMQ
一 RabbitMQ的介绍 RabbitMQ是消息中间件的一种,消息中间件即分布式系统中完成消息的发送和接收的基础软件.这些软件有很多,包括ActiveMQ(apache公司的),RocketMQ(阿 ...
- Rabbitmq基本使用 SpringBoot整合Rabbit SpringCloud Stream+Rabbit
https://blog.csdn.net/m0_37867405/article/details/80793601 四.docker中使用rabbitmq 1. 搭建和启动 使用地址:rabbitm ...
- 【SpringBoot系列5】SpringBoot整合RabbitMQ
前言: 因为项目需要用到RabbitMQ,前几天就看了看RabbitMQ的知识,记录下SpringBoot整合RabbitMQ的过程. 给出两个网址: RabbitMQ官方教程:http://www. ...
- SpringBoot系列八:SpringBoot整合消息服务(SpringBoot 整合 ActiveMQ、SpringBoot 整合 RabbitMQ、SpringBoot 整合 Kafka)
声明:本文来源于MLDN培训视频的课堂笔记,写在这里只是为了方便查阅. 1.概念:SpringBoot 整合消息服务 2.具体内容 对于异步消息组件在实际的应用之中会有两类: · JMS:代表作就是 ...
随机推荐
- 高德地图的权限Activity代码
/** * */package com.amap.location.demo; import java.lang.reflect.Method;import java.util.ArrayList;i ...
- rest framework之渲染器
一.内置渲染器 REST框架包括许多内置的Renderer类,它们允许你使用各种媒体类型返回响应.还支持定义你自己的自定义渲染器. 内置渲染器的使用 1.全局设置 可以使用DEFAULT_RENDER ...
- vuex之module的使用
一.module的作用 由于使用单一状态树,应用的所有状态会集中到一个比较大的对象.当应用变得非常复杂时,store 对象就有可能变得相当臃肿. 为了解决以上问题,Vuex 允许我们将 store 分 ...
- bcpow — 任意精度数字的乘方
bcpow — 任意精度数字的乘方 说明 string bcpow ( string $left_operand , string $right_operand [, int $scale ] ) 左 ...
- Java中的内部类怎么用
一.为什么需要内部类?java内部类有什么好处?为什么需要内部类? 首先举一个简单的例子,如果你想实现一个接口,但是这个接口中的一个方法和你构想的这个类中的一个方法的名称,参数相同,你应该怎么办?这时 ...
- ECMAScript 6学习总结
学习ECMAScript 6 一.什么是ES6 ECMAScript6是ECMAScript的升级,实现用来编写复杂程序项目. 二.ECMAScript和JavaScript的关系 JavaScrip ...
- open source library
{ https://gitee.com/tboox https://github.com/thejinchao/cyclone http://www.drchip.org/astronaut/ssl/ ...
- PHP ftp_login() 函数
定义和用法 ftp_login() 函数登录 FTP 服务器. 如果成功,该函数返回 TRUE.如果失败,则返回 FALSE 和一个警告. 语法 ftp_login(ftp_connection,us ...
- C++语言编程基础
C++程序设计语言可以看作C语言的改进和升级,不仅完全兼容了C语言的语法和函数库,还引入了面向对象.运算符重载.多态性.数据流和模板等最新的编程思想.极大地保证了源代码的生产率.质量和可重用性.GNU ...
- opencv bwlabel
int bwLabel(const Mat& imgBw, Mat& imgLabeled) { Mat imgClone = Mat(imgBw.rows + , imgBw.col ...