RabbitMQ与SpringBoot整合

256 阅读5分钟

RabbitMQ消息队列

为什么使用MQ?
  1. 异步提速
  2. 应用解耦
  3. 削峰填谷
  4. 保证有序性
  5. 可恢复性
消息队列的产品
  1. RabbitMQ:基于JMS实现, 比较均衡, 不是最快的, 也不是最稳定的
  2. ActiveMQ
  3. RocketMQ:基于JMS,阿里巴巴产品,目前已经捐献给apahce, 还在孵化器中孵化.
  4. Kafaka:类似MQ的产品;分布式消息系统,高吞吐量, 目前最快的消息服务器, 不保证数据完整性
  5. ZeroMQ
AMQP和JMS
  1. AMQP协议:一个提供统一消息服务的应用层标准高级消息队列协议,是应用层协议的一个开放标准,为面向消息的中间件设计
    • 跨语言
    • 跨平台
  2. JMS:JMS即Java消息服务(JavaMessage Service)应用程序接口,是一个Java平台中关于面向消息中间件 (MOM)的API,用于在两个应用程序之间,或分布式系统中发送消息,进行异步通信
    • 只适用于java
应用场景
  1. 双十一商品秒杀/抢票功能实现
  2. 积分兑换(积分可用于多平台)
    • 积分兑换模块,有一个公司多个部门都要用到这个模块,这时候就可以通过消息队列解耦这个特性来实 现。 各部门系统做各部门的事,但是他们都可以用这个积分系统进行商品的兑换等。其他模块与积分模 块完全解耦。
  3. 大平台用户注册:用户大数据分析、发送邮件
    • 用户注册真实操作步骤:
      1. 注册后需要送短信给用户
      2. 可能发送邮件给用户
      3. 用户注册选择的兴趣标签,进行用户分析,推荐内容
      4. 发送给用户指南的系统通知
Rabbit结构图

rabbit结构图.png

  1. Producer:消息的提供者
  2. Connection:publisher/consumer 和 broker 之间的 TCP 连接
    • Channel: 消息通道,在客户端的每个连接里,可建立多个channel,每个channel代表一个会话 任务
  3. broker:RabbitMQ Server
    • VHost: 虚拟主机,一个broker里可以开设多个vhost,用作不同用户的权限分离
      • Exchange:消息交换机,它指定消息按什么规则,路由到哪个队列
      • Queue:消息队列载体,每个消息都会被投入到一个或多个队列
  4. Consumer:消息的消费者

Spring Boot整合RabbitMQ

1. Product
<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>2.1.9.RELEASE</version>
    <relativePath/>
</parent>
<dependencies>
	<!--amqp协议的起步依赖坐标-->
	<dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-amqp</artifactId>
    </dependency>
    <!--rabbit测试依赖坐标-->
    <dependency>
        <groupId>org.springframework.amqp</groupId>
        <artifactId>spring-rabbit-test</artifactId>
        <scope>test</scope>
    </dependency>
    <!--SpringBoot测试依赖坐标-->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-test</artifactId>
        <scope>test</scope>
    </dependency>
</dependencies>
spring:
  rabbitmq:
    host: xxx.xxx.xxx.xxx
    port: 5672
    virtual-host: /wangqyjs
    username: guest
    password: guest
2. Consumer
<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>2.1.9.RELEASE</version>
    <relativePath/>
</parent>
<dependencies>
	<!--amqp协议的起步依赖坐标-->
	<dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-amqp</artifactId>
    </dependency>
</dependencies>
spring:
  rabbitmq:
    host: xxx.xxx.xxx.xxx
    port: 5672
    virtual-host: /wangqyjs
    username: guest
    password: guest

RabbitMQ五种工作模式

1. 简单模式

rabbit简单模式.png

  • 有一个默认交换机

  • 创建queue

    • Type : Classic

    • Name:自定义(simple_queue)

  • 生产者代码:向simple_queue发送100条数据

    @RunWith(SpringRunner.class)
    @SpringBootTest
    public class RabbitmqProductorApplicationTests {
    
        @Autowired
        private RabbitTemplate rabbitTemplate;
    
    
        @Test
        public void testSimpleQueue() {
            for (int i = 0; i < 100; i++) {
                rabbitTemplate.convertAndSend("simple_queue","测试simplequeue"+i);
            }
        }
    
    }
    
  • 消费者代码:创建监听器

    • @RabbitListener(queues = "simple_queue")
    • @RabbitHandler
    @Component
    @RabbitListener(queues = "simple_queue")
    public class SimpleListener {
    
        @RabbitHandler
        public void simpleHandler(String msg) {
            System.out.println(msg);
        }
    
    }
    
2. Work queues工作队列模式

rabbit工作队列模式.png

  • 有一个默认交换机

  • 该模式,创建的消息会平均分配给监听者处理。

  • 创建queue

    • Type : Classic
    • Name:自定义(work_queue)
  • 生产者代码:向simple_queue发送100条数据

    @RunWith(SpringRunner.class)
    @SpringBootTest
    public class RabbitmqProductorApplicationTests {
    
        @Autowired
        private RabbitTemplate rabbitTemplate;
    
    
        @Test
        public void testSimpleQueue() {
            for (int i = 0; i < 100; i++) {
                rabbitTemplate.convertAndSend("work_queue","测试workqueue"+i);
            }
        }
    
    }
    
  • 消费者代码

    @Component
    @RabbitListener(queues = "work_queue")
    public class WorkListener1 {
    
        @RabbitHandler
        public void workQueueHandler(String msg) {
            System.out.println("workQueueHandler1 处理了" + msg);
        }
    
    }
    
    @Component
    @RabbitListener(queues = "work_queue")
    public class WorkListener2 {
    
        @RabbitHandler
        public void workQueueHandler(String msg) {
            System.out.println("workQueueHandler2 处理了" + msg);
        }
        
    }
    
3. 发布订阅模式Publish/Subscribe

rabbit发布订阅模式.png

  • 交换机绑定多个队列,交换机接受的消息会发送给所有绑定的队列

  • 该方式实现异步解耦

  • 每个消费者监听自己的队列

  • 生产者将消息发给broker,由交换机将消息转发到绑定此交换机的每个队列,每个绑定交换机的 队列都将接收到消息

  • 创建queue

    • Type : Classic
    • Name:自定义(fanout_queue1
    • Name:自定义(fanout_queue2
  • 创建exchange

    • Name:fanout_exchange
    • Type:fanout
    • Bingings:fanout_queue1、fanout_queue2
  • 生产者代码

    • exchange 指定交换器
    • routingKey 路由键设定为 ”“
    • object 发送的内容
    @RunWith(SpringRunner.class)
    @SpringBootTest
    public class RabbitmqProductorApplicationTests {
    
        @Autowired
        private RabbitTemplate rabbitTemplate;
    
    
        @Test
        public void fanoutTest() {
            for (int i = 0; i < 100; i++) {
                rabbitTemplate.convertAndSend("fanout_exchange","","测试fanout_exchange"+i);
            }
        }
    
    }
    
  • 消费者代码

    @Component
    @RabbitListener(queues = "fanout_queue1")
    public class fanoutQueue1 {
    
        @RabbitHandler
        public void fanoutHandler(String msg) {
            System.out.println(msg);
        }
    }
    
    @Component
    @RabbitListener(queues = "fanout_queue2")
    public class fanoutQueue2 {
    
        @RabbitHandler
        public void fanoutHandler(String msg) {
            System.out.println(msg);
        }
    }
    
4. Routing路由模式

rabbit路由模式.png

  • 队列与交换机的绑定,而是要指定一个RoutingKey

  • 创建queue

    • Type : Classic
    • Name:自定义(routing_queue1
    • Name:自定义(routing_queue2
    • Name:自定义(routing_queue3
  • 创建exchange

    • Name:routing_exchange
    • Type:direct
    • Bingings:routing_queue1、routing_queue2、routing_queue3
  • 消息的发布者代码

    @RestController
    public class ExchangeQueueController {
    
        @Autowired
        private RabbitTemplate rabbitTemplate;
    
        @RequestMapping("/rabbit/info")
        public String testRountingC(@RequestParam String exchange, @RequestParam String routingKey, @RequestParam String msg){
            System.out.println(exchange);
            System.out.println(routingKey);
            System.out.println(msg);
            rabbitTemplate.convertAndSend(exchange,routingKey,msg);
            return "发送成功";
        }
    
    }
    
  • 消息的消费者代码

    @Component
    @RabbitListener(queues = "routing_queue1")
    public class RountingQueue1 {
    
        @RabbitHandler
        public void rountingQueueTest(String msg){
            System.out.println("rounting_queue1处理" + msg);
        }
    
    }
    @Component
    @RabbitListener(queues = "routing_queue2")
    public class RountingQueue2 {
    
        @RabbitHandler
        public void rountingQueueTest(String msg){
            System.out.println("rounting_queue2处理" + msg);
        }
    
    }
    @Component
    @RabbitListener(queues = "routing_queue3")
    public class RountingQueue3 {
    
        @RabbitHandler
        public void rountingQueueTest(String msg){
            System.out.println("rounting_queue3处理" + msg);
        }
    
    }
    
5. Topics通配符模式

rabbit通配符模式.png

  • 队列与交换机的绑定,而是要指定一个RoutingKey

    • #:匹配一个或多个词,多个词用点号分隔
    • *:匹配不多不少恰好1个词
  • 创建queue

    • Type : Classic
    • Name:自定义(topic_queue1
    • Name:自定义(topic_queue2
  • 创建exchange

    • Name:topic_exchange
    • Type:topic
    • Bingings:topic_queue1、topic_queue2
  • 消息的发布者代码

    @RestController
    public class ExchangeQueueController {
    
        @Autowired
        private RabbitTemplate rabbitTemplate;
    
        @RequestMapping("/rabbit/info")
        public String testRountingC(@RequestParam String exchange, @RequestParam String routingKey, @RequestParam String msg){
            System.out.println(exchange);
            System.out.println(routingKey);
            System.out.println(msg);
            rabbitTemplate.convertAndSend(exchange,routingKey,msg);
            return "发送成功";
        }
    
    }
    
  • 消息的消费者代码

    @Component
    @RabbitListener(queues = "topic_queue1")
    public class TopicQueue1 {
    
        @RabbitHandler
        public void topicHandler(String msg) {
            System.out.println("topic_queue1  "+msg);
        }
    
    }
    @Component
    @RabbitListener(queues = "topic_queue2")
    public class TopicQueue2 {
    
        @RabbitHandler
        public void topicHandler(String msg) {
            System.out.println("topic_queue2  "+msg);
        }
    
    }