添加rabbitmq的依赖

  1. <dependency>
  2. <groupId>org.springframework.boot</groupId>
  3. <artifactId>spring-boot-starter-amqp</artifactId>
  4. </dependency>

在配置文件中添加必要的配置信息

  1. spring.rabbitmq.host=192.168.0.86
  2. spring.rabbitmq.port=5672
  3. spring.rabbitmq.username=admin
  4. spring.rabbitmq.password=123456

好了,基本的配置就已经配置完毕了

rabbitmq有六种模式

我们逐个来看springboot是怎么实现的呢

1.hello world

P代表生产者,C代表消费者,红色代码消息队列。P将消息发送到消息队列,C对消息进行处理。

我们先创建一个队列

  1. @Bean
  2. public Queue Queue() {
  3. return new Queue("hello");
  4. }

然后我再创建一个生产者

  1. @Controller
  2. public class HelloSender {
  3.  
  4. @Autowired
  5. private AmqpTemplate rabbitTemplate;
  6.  
  7. public void send() {
  8. String context = "hello " + new Date();
  9. System.out.println("Sender : " + context);
  10. this.rabbitTemplate.convertAndSend("hello", context);
  11. }
  12. }

再创建一个消费者

  1. @Component
  2. @RabbitListener(queues = "hello")
  3. public class HelloReceiver {
  4. @RabbitHandler
  5. public void process(String hello) {
  6. System.out.println("Receiver : " + hello);
  7. }
  8. }

再写一个测试用例看看

  1. @RunWith(SpringRunner.class)
  2. @SpringBootTest
  3. public class RabbitmqApplicationTests {
  4. @Autowired
  5. private HelloSender helloSender;
  6.  
  7. @Test
  8. public void hello() throws Exception {
  9. helloSender.send();
  10. }
  11. }

成功!

2.工作模式(竞争)

一个消息产生者,多个消息的消费者。竞争抢消息

我们先创建一个队列

  1. @Bean
  2. public Queue Queue2() {
  3. return new Queue("neo");
  4. }

再创建一个消息生产者

  1. @Controller
  2. public class NeoSender {
  3. @Autowired
  4. private AmqpTemplate rabbitTemplate;
  5.  
  6. public void send(int i) {
  7. String context = "spirng boot neo queue"+" ****** "+i;
  8. System.out.println("Sender1 : " + context);
  9. this.rabbitTemplate.convertAndSend("neo", context);
  10. }
  11. }

再创建两个消息的消费者

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

我们写一个测试用例

  1. @Test
  2. public void oneToMany() throws Exception {
  3. for (int i=0;i<100;i++){
  4. // Thread.sleep(10);
  5. neoSender.send(i);
  6. }
  7. }

运行

可以看到消息均匀的被两个消费者消费了。

通过这个例子我们可以看做高并发情况下的消息产生和消费,这会产生一个消息丢失的问题。万一客户端在处理消息的时候挂了,那这条消息就相当于被浪费了,针对这种情况,rabbitmq推出了消息ack机制,熟悉tcp三次握手的一定不会陌生。

我们看看springboot是实现ack的

很简单,在我们的配置类中,配置一个新的消费者,将原先的消费者先都去掉:

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

但这里会有个问题,test模式下消息发送完毕系统就会直接shutdown,所以只能消费部分消息,不过等真正启动项目,这个问题就不存在了。

3.发布订阅模式

生产者将消息不是直接发送到队列,而是发送到X交换机,然后由交换机发送给两个队列,两个消费者各自监听一个队列,来消费消息。

这种方式实现同一个消息被多个消费者消费。工作模式是同一个消息只能有一个消费者。

我们新建三个队列

  1. @Bean
  2. public Queue AMessage() {
  3. return new Queue("fanout.A");
  4. }
  5.  
  6. @Bean
  7. public Queue BMessage() {
  8. return new Queue("fanout.B");
  9. }
  10.  
  11. @Bean
  12. public Queue CMessage() {
  13. return new Queue("fanout.C");
  14. }

再新建一个交换机

  1. @Bean
  2. FanoutExchange fanoutExchange() {
  3. return new FanoutExchange("fanoutExchange");
  4. }

再把这些队列绑定到交换机上去

  1. @Bean
  2. Binding bindingExchangeA(Queue AMessage, FanoutExchange fanoutExchange) {
  3. return BindingBuilder.bind(AMessage).to(fanoutExchange);
  4. }
  5.  
  6. @Bean
  7. Binding bindingExchangeB(Queue BMessage, FanoutExchange fanoutExchange) {
  8. return BindingBuilder.bind(BMessage).to(fanoutExchange);
  9. }
  10.  
  11. @Bean
  12. Binding bindingExchangeC(Queue CMessage, FanoutExchange fanoutExchange) {
  13. return BindingBuilder.bind(CMessage).to(fanoutExchange);
  14. }

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

  1. @Component
  2. public class FanoutSender {
  3. @Autowired
  4. private AmqpTemplate rabbitTemplate;
  5.  
  6. public void send() {
  7. String context = "hi, fanout msg ";
  8. System.out.println("Sender : " + context);
  9. this.rabbitTemplate.convertAndSend("fanoutExchange","", context);
  10. }
  11. }

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

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

三个消费者分别监听3个队列的内容

新建一个测试用例:

  1. @RunWith(SpringRunner.class)
  2. @SpringBootTest
  3. public class FanoutTest {
  4. @Autowired
  5. private FanoutSender fanoutSender;
  6.  
  7. @Test
  8. public void setFanoutSender(){
  9. fanoutSender.send();
  10. }
  11.  
  12. }

三个队列都接受到了消息

4:路由模式

需要将一个队列绑定到交换机上,要求该消息与一个特定的路由键完全匹配,这是一个完整的匹配。

5.主题模式

发送端不只按固定的routing key发送消息,而是按字符串匹配发送,接收端同样如此

符号#匹配一个或多个词,符号*匹配不多不少一个词。

4/5两者模式很相似,我们放在一起演示

新建两个队列

  1. final static String message = "topic.A";
  2. final static String messages = "topic.B";
  3.  
  4. @Bean
  5. public Queue queueMessage() {
  6. return new Queue(TopicRabbitConfig.message);
  7. }
  8.  
  9. @Bean
  10. public Queue queueMessages() {
  11. return new Queue(TopicRabbitConfig.messages);
  12. }

新建一个交换机

  1. @Bean
  2. TopicExchange exchange() {
  3. return new TopicExchange("topicExchange");
  4. }

绑定队列到交换机上,路由模式,需要完整匹配topic.message,才能接受

  1. @Bean
  2. Binding bindingExchangeMessage(Queue queueMessage, TopicExchange exchange) {
  3. return BindingBuilder.bind(queueMessage).to(exchange).with("topic.message");
  4. }

topic模式,前缀匹配到topic.即可接受

  1. @Bean
  2. Binding bindingExchangeMessages(Queue queueMessages, TopicExchange exchange) {
  3. return BindingBuilder.bind(queueMessages).to(exchange).with("topic.#");
  4. }

我们新建三个消息生产者

  1. @Component
  2. public class TopicSend {
  3. @Autowired
  4. private AmqpTemplate rabbitTemplate;
  5.  
  6. public void send() {
  7. String context = "hi, i am message all";
  8. System.out.println("Sender : " + context);
  9. this.rabbitTemplate.convertAndSend("topicExchange", "topic.1", context);
  10. }
  11.  
  12. public void send1() {
  13. String context = "hi, i am message 1";
  14. System.out.println("Sender : " + context);
  15. this.rabbitTemplate.convertAndSend("topicExchange", "topic.message", context);
  16. }
  17.  
  18. public void send2() {
  19. String context = "hi, i am messages 2";
  20. System.out.println("Sender : " + context);
  21. this.rabbitTemplate.convertAndSend("topicExchange", "topic.messages", context);
  22. }
  23. }

send的key是topic.1  send1的key是topic.message,send2的key是topic.messages

所以理论上send会被两个队列消费,1.2都应该只有一个队列消费

我们再新建两个消费者

  1. @Component
  2. @RabbitListener(queues = "topic.A")
  3. public class TopicReceiver {
  4. @RabbitHandler
  5. public void process(String message) {
  6. System.out.println("Topic Receiver1 : " + message);
  7. }
  8.  
  9. }
  10.  
  11. @Component
  12. @RabbitListener(queues = "topic.B")
  13. public class TopicReceiver2 {
  14. @RabbitHandler
  15. public void process(String message) {
  16. System.out.println("Topic Receiver2 : " + message);
  17. }
  18. }

写三个测试用例

  1. @RunWith(SpringRunner.class)
  2. @SpringBootTest
  3. public class TopicTest {
  4. @Autowired
  5. private TopicSend sender;
  6.  
  7. @Test
  8. public void topic() throws Exception {
  9. sender.send();
  10. }
  11.  
  12. @Test
  13. public void topic1() throws Exception {
  14. sender.send1();
  15. }
  16.  
  17. @Test
  18. public void topic2() throws Exception {
  19. sender.send2();
  20. }
  21.  
  22. }

send的运行结果

send1的运行结果

send2的运行结果

结果符合预期。

转自:https://www.cnblogs.com/xmzJava/p/8036591.html

【RabbitMQ】六种模式与SpringBoot整合的更多相关文章

  1. 一篇学习完rabbitmq基础知识,springboot整合rabbitmq

    一   rabbitmq 介绍 MQ全称为Message Queue,即消息队列, RabbitMQ是由erlang语言开发,基于AMQP(Advanced MessageQueue 高级消息队列协议 ...

  2. 初窥RabbitMQ消息中间及SpringBoot整合

    一:RabbitMQ简介 RabbitMQ介绍 RabbitMQ 即一个消息队列,主要是用来实现应用程序的异步和解耦,同时也能起到消息缓冲,消息分发的作用. 消息中间件最主要的作用是解耦,中间件最标准 ...

  3. RabbitMQ基础组件和SpringBoot整合RabbitMQ简单示例

    交换器(Exchange) 交换器就像路由器,我们先是把消息发到交换器,然后交换器再根据绑定键(binding key)和生产者发送消息时的路由键routingKey, 按照交换类型Exchange ...

  4. SpringBoot整合RabbitMQ实现六种工作模式

    RabbitMQ主要有六种种工作模式,本文整合SpringBoot分别介绍工作模式的实现. 前提概念 生产者 消息生产者或者发送者,使用P表示: 队列 消息从生产端发送到消费端,一定要通过队列转发,使 ...

  5. RabbitMQ与SpringBoot整合

    RabbitMQ  SpringBoot  一.RabbitMQ的介绍 二.Direct模式 三.Topic转发模式 四.Fanout Exchange形式 原文地址: https://www.cnb ...

  6. springboot学习笔记-6 springboot整合RabbitMQ

    一 RabbitMQ的介绍 RabbitMQ是消息中间件的一种,消息中间件即分布式系统中完成消息的发送和接收的基础软件.这些软件有很多,包括ActiveMQ(apache公司的),RocketMQ(阿 ...

  7. Rabbitmq基本使用 SpringBoot整合Rabbit SpringCloud Stream+Rabbit

    https://blog.csdn.net/m0_37867405/article/details/80793601 四.docker中使用rabbitmq 1. 搭建和启动 使用地址:rabbitm ...

  8. 【SpringBoot系列5】SpringBoot整合RabbitMQ

    前言: 因为项目需要用到RabbitMQ,前几天就看了看RabbitMQ的知识,记录下SpringBoot整合RabbitMQ的过程. 给出两个网址: RabbitMQ官方教程:http://www. ...

  9. SpringBoot系列八:SpringBoot整合消息服务(SpringBoot 整合 ActiveMQ、SpringBoot 整合 RabbitMQ、SpringBoot 整合 Kafka)

    声明:本文来源于MLDN培训视频的课堂笔记,写在这里只是为了方便查阅. 1.概念:SpringBoot 整合消息服务 2.具体内容 对于异步消息组件在实际的应用之中会有两类: · JMS:代表作就是 ...

随机推荐

  1. 高德地图的权限Activity代码

    /** * */package com.amap.location.demo; import java.lang.reflect.Method;import java.util.ArrayList;i ...

  2. rest framework之渲染器

    一.内置渲染器 REST框架包括许多内置的Renderer类,它们允许你使用各种媒体类型返回响应.还支持定义你自己的自定义渲染器. 内置渲染器的使用 1.全局设置 可以使用DEFAULT_RENDER ...

  3. vuex之module的使用

    一.module的作用 由于使用单一状态树,应用的所有状态会集中到一个比较大的对象.当应用变得非常复杂时,store 对象就有可能变得相当臃肿. 为了解决以上问题,Vuex 允许我们将 store 分 ...

  4. bcpow — 任意精度数字的乘方

    bcpow — 任意精度数字的乘方 说明 string bcpow ( string $left_operand , string $right_operand [, int $scale ] ) 左 ...

  5. Java中的内部类怎么用

    一.为什么需要内部类?java内部类有什么好处?为什么需要内部类? 首先举一个简单的例子,如果你想实现一个接口,但是这个接口中的一个方法和你构想的这个类中的一个方法的名称,参数相同,你应该怎么办?这时 ...

  6. ECMAScript 6学习总结

    学习ECMAScript 6 一.什么是ES6 ECMAScript6是ECMAScript的升级,实现用来编写复杂程序项目. 二.ECMAScript和JavaScript的关系 JavaScrip ...

  7. open source library

    { https://gitee.com/tboox https://github.com/thejinchao/cyclone http://www.drchip.org/astronaut/ssl/ ...

  8. PHP ftp_login() 函数

    定义和用法 ftp_login() 函数登录 FTP 服务器. 如果成功,该函数返回 TRUE.如果失败,则返回 FALSE 和一个警告. 语法 ftp_login(ftp_connection,us ...

  9. C++语言编程基础

    C++程序设计语言可以看作C语言的改进和升级,不仅完全兼容了C语言的语法和函数库,还引入了面向对象.运算符重载.多态性.数据流和模板等最新的编程思想.极大地保证了源代码的生产率.质量和可重用性.GNU ...

  10. opencv bwlabel

    int bwLabel(const Mat& imgBw, Mat& imgLabeled) { Mat imgClone = Mat(imgBw.rows + , imgBw.col ...