Springboot系列(十七):Springboot整合RabbitMq

1,503 阅读13分钟

👨‍🎓作者:bug菌
✏️博客:CSDN掘金infoQ51CTO
🎉简介:CSDN博客专家,C站历届博客之星Top50,掘金/InfoQ/51CTO等社区优质创作者,全网合计8w粉+,对一切技术感兴趣,重心偏Java方向;硬核公众号「 猿圈奇妙屋」,欢迎小伙伴们的加入,一起秃头,一起变强。
..
✍️温馨提醒:本文字数:1999字, 阅读完需:约 5 分钟

       嗨,家人们,我是bug菌呀,我又来啦。今天我们来聊点什么咧,OK,接着为大家更《springboot零基础入门教学》系列文章吧。希望能帮助更多的初学者们快速入门!

       小伙伴们在批阅文章的过程中如果觉得文章对您有一丝丝帮助,还请别吝啬您手里的赞呀,大胆的把文章点亮👍吧,您的点赞三连(收藏⭐+关注👨‍🎓+留言📃)就是对bug菌我创作道路上最好的鼓励与支持😘。时光不弃🏃🏻‍♀️,创作不停💕,加油☘️

一、前言🔥

环境说明:Windows10 + Idea2021.3.2 + Jdk1.8 + SpringBoot 2.3.1.RELEASE

       之前我在开发商城项目的时候,有接触过这么一块订单与库存模板,由于并发不是很大就一直搁置,然后我现在回想起来,完全可以用现在的高性能中间件来处理以降低两模块之间的耦合度,这也是我今天要介绍的东西--消息中间件之消息队列[RabbitMq],闲暇时间对此有进行一些学习了解☃️,下面是学习内容的总结。

       借此想分享给大家, 希望能帮助那些还未入门的小伙伴们,在学完本期文章内容,你将会对RabbitMq有一个基本的认识,而不再是它认识你,你不认识它。具有很好的学习价值,大家请跟我来吧👀。

       在此之前,请大家先安装好RabbitMq Server服务端,否则后边没法玩儿啦,推荐大家看我上期为大家准备的安装篇,非常详细《Windows10本地搭建RabbitMq Server服务端》

二、概念

       下面,我先来给大家科普一下,消息队列相关的一些基础概念吧。使用前先了解它是什么,为什么用它,它有那些优劣,什么场景下使用适合等,带着这些疑问来本文探寻吧,对你日后开发使用也是及有帮助🔮。

1、什么是消息队列

       首先我们先来解读一下什么是消息(Message)。指在应用之间传送的数据被称为消息。消息的内容可以非常简单,比如只包含文本字符串,也可以非常的复杂,比如包含嵌入对象,根据你实际场景而定。 

       消息队列(Message Queue)则是一种应用之间的通信方式。消息发送后可以立即返回,由消息系统来确保信息的可靠传输。消息发布者只需把消息发布并传送到队列中,消息使用者只管从队列中取走消息并处理,这样发布者和使用者都不需要知道对方的存在,从而达到解耦的目的。

2、为什么要使用消息队列

  • **提高系统响应速度
    **

       使用消息队列,生产者一方,把消息往消息队列里一扔,就可以立马返回响应用户,无需等待处理结果

  • **保证消息的传递
    **

       如果发送消息时接收者不可用,消息队列会保留消息,直到成功传递它为止。

  • 解耦

       只要信息格式不变,即使接收者的接口、位置、或者配置改变,也不会给发送者带来任何改变 消息发送者无需知道消息接收者是谁,使得系统设计更清晰 。

3、RabbitMq是什么

       RabbitMq属于消息队列的一种。对于消息队列,我们一般知道有三个概念:发消息者、队列、收消息者,RabbitMQ 在这个基本概念之上,多做了一层抽象,在发消息者和队列之间,加入了交换器(Exchange)这样发消息者和队列就没有直接联系,转而变成发消息者把消息给交换器,交换器根据调度策略再把消息再给队列。

RabbitMQ是一个由 Erlang 开发的AMQP(Advanced Message Queuing Protocol)开源实现。服务器端用Erlang语言编写,支持多种客户端,比如:Python、Java、PHP、C等,且支持Ajax。在分布式系统中对消息的存储转发,在易用性、扩展性、高可用性等方面上也表现不俗。

       RabbitMQ主要是用来实现应用程序的异步和解耦,同时也能起到消息缓冲,消息分发的作用。

拓展:
AMQP:高级消息队列协议,是应用层协议的一个开放标准,为面向消息的中间件设计。

4、RabbitMQ的特点

  • 可靠性

       RabbitMQ 使用一些机制来保证可靠性,如持久化、传输确认、发布确认等。

  • 灵活路由

       在消息进入队列之前,通过 Exchange 来路由消息的。对于典型的路由功能,RabbitMQ 已经提供了一些内置的 Exchange 来实现。针对更复杂的路由功能,可以将多个 Exchange 绑定在一起,也通过插件机制实现自己的 Exchange 。

  • 消息集群

       多个 RabbitMQ 服务器可以组成一个集群,形成一个逻辑 Broker 。

  • 高可用

       队列可以在集群中的机器上进行镜像,使得在部分节点出问题的情况下队列仍然可用。

  • 多种协议

       RabbitMQ 支持多种消息队列协议,比如 STOMP、MQTT 等等。

  • 多语言客户端

       RabbitMQ 几乎支持所有常用语言,比如 Java、.NET、Ruby 等等

  • 管理界面

       RabbitMQ 提供了一个易用的用户界面,使得用户可以监控和管理消息 Broker 的许多方面。

  • 跟踪机制

       如果消息异常,RabbitMQ 提供了消息跟踪机制,使用者可以找出发生了什么。

  • 插件机制

       RabbitMQ 提供了许多插件,来从多方面进行扩展,也可以编写自己的插件。

5、RabbitMQ 基本概念

  • Message

       消息,消息是不具名的,它由消息头和消息体组成。消息体是不透明的,而消息头则由一系列的可选属性组成,这些属性包括routing-key(路由键)、priority(相对于其他消息的优先权)、delivery-mode(指出该消息可能需要持久性存储)等。

  • Publisher

       消息的生产者,也是一个向交换器发布消息的客户端应用程序。

  • Exchange

       交换器,用来接收生产者发送的消息并将这些消息路由给服务器中的队列。

  • Routing Key

       路由关键字,exchange根据这个关键字进行消息投递。

  • Binding

       绑定,用于消息队列和交换器之间的关联。一个绑定就是基于路由键将交换器和消息队列连接起来的路由规则,所以可以将交换器理解成一个由绑定构成的路由表。

  • Queue

       消息队列,用来保存消息直到发送给消费者。它是消息的容器,也是消息的终点。一个消息可投入一个或多个队列。消息一直在队列里面,等待消费者连接到这个队列将其取走。

  • Broker

       表示消息队列服务器实体。

... ...

6、RabbitMQ的应用场景

  • 异步处理

场景:用户注册

用户注册后,需要发注册邮件和注册短信,传统的做法有两种1.串行的方式;2.并行的方式 。

引入消息队列后:

可以把发送邮件,短信不是必须的业务逻辑异步处理。

  • 应用解耦

场景:比如商城的订单系统与库存系统。

       传统是用户下单后,订单系统需要通知库存系统,传统的做法就是订单系统调用库存系统的接口。这样做法的有个严重的弊端:当库存系统出现故障时,订单就会失败。

引入消息队列后:

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

  • 流量削峰

场景:比如秒杀活动。

一般会因为流量过大,导致应用挂掉,为了解决这个问题,一般在应用前端加入消息队列。

引入消息队列后:

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

三、本地安装RabbitMq客户端

这里推荐大家看我上期写的搭建教程:《Windows10本地搭建RabbitMq Server服务端》

我就不给安装大家演示啦。归纳总结主要就是如下两点安装步骤。

然后附上了官网下载地址,方便大家下载使用。

  1. 安装erlang环境
  2. 安装RabbitMq客户端

四、添加RabbitMq依赖

       springboot也对RabbitMq做了相应的集成,所以我们直接拿来用就可以了,在你们的pom.xml配置中直接添加如下配置即可。

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

五、简单Rabbit使用演示

第一步:配置mq服务

spring:
  #配置rabbitMq 服务器
  rabbitmq:
    #设置RabbitMQ的IP地址
    host: 127.0.0.1
    #设置rabbitmq服务器连接端口
    port: 5672
    #设置rabbitmq服务器用户名  本地搭建对应的账户密码都是 guest
    username: guest
    #设置rabbitmq服务器密码
    password: guest

拓展:
如果修改过IP、端口号、账号、密码以上内容则需要重新指定。未修改都是如下默认:

  • 默认使用IP:127.0.0.1

  • 默认使用端口号:5672

  • 默认使用账号:guest

  • 默认使用密码:guest

  • 15672:控制台端口号

  • 5672:应用访问端口号  //所以配置文件配置的端口是5672而不是15672.

如上就已经配置连接了Server端,查看是否能正常连接,就看生产者能否往队列里发消息了。

第二步:RabbitMq配置

       这里我们先来定义一个Rabbitmq配置类,目的是先定义好一个队列,待会儿就直接往这个队列中写入消息。

package com.example.demo.config;

import org.springframework.amqp.core.Queue;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

/**
 * 声明一个队列
 *
 * @author luoYong
 * @version 1.0
 * @date 2022/2/24 17:10
 */
@Configuration
public class RabbitMqConfig {

    /**
     * 初始化Queue
     * 创建一个名称为"luoyong-queue"的队列,其他参数使用默认
     * 在创建队列的时候如果要指定其他参数,Queue有多个构造方法可选择
     */
    @Bean
    public Queue helloQueue() {
        return new Queue("luoyong-queue");
    }
}

       接下来,我给大家演示一下RabbitMQ 的五种工作模式之最简单的--简单队列

一个生产者只对应一个消费者!我们先来定义一个生产者。

具体实现代码如下:

package com.example.demo.component.RabbitMq;

import org.springframework.amqp.core.AmqpTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

/**
 * 生产者
 *
 * @author luoYong
 * @version 1.0
 * @date 2022/2/24 17:16
 */
@Component
public class RabbitSender {

    @Autowired
    private AmqpTemplate rabbitTemplate;

    /**
     * 发送消息
     */
    public void sendMsg() {
        String msg = "简单队列-hello呀";
        System.out.println("Sender : " + msg);
        this.rabbitTemplate.convertAndSend("luoyong-queue", msg);
    }
}

       在简单队列模型中,发送消息的时候不指定交换机的名称,那么就会发送到"默认交换机"上。默认的Exchange不进行Binding操作,任何发送到该Exchange的消息都会被转发到"Queue名字和Routing key相同的队列"中,如果vhost中不存在和Routing key同名的队列,则该消息会被抛弃。 

       这里我们在发送消息的时候设置的Routing key为"luoyong-queue",那么就会发送到队列名字为"felix-queue"的队列上去。

我们再来定义一个 消费者。

具体实现代码如下:

package com.example.demo.component.RabbitMq;

import org.springframework.amqp.rabbit.annotation.RabbitHandler;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Component;

/**
 * 消费者
 *
 * @author luoYong
 * @version 1.0
 * @date
 2022/2/24 17:19
 */
@Component
@RabbitListener(queues = "luoyong-queue")  //指定队列
public class RabbitReceiver {

    @RabbitHandler
    public void process(String msg) {
        System.out.println("Receiver  : 消费成功:" + msg);
    }
}

 接下来我们来定义一个测试类,测试生产者发送消息功能。

package com.example.demo.component.RabbitMq;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;

/**
 * @author luoYong
 * @version 1.0
 * @date 2022/2/24 17:02
 */
@RunWith(SpringRunner.class)
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
public class RabbitMqConfigTest {

    @Autowired
    private RabbitSender rabbitSender;

    // 发送单条消息
    @Test
    public void contextLoads() {
        rabbitSender.sendMsg();
    }
}

第三步:测试生产者

1、测试生产者

        测试类启动运行之后,登陆Server端界面,可以看到队列中阻塞了一条消息未消费。

只要未被消费,就一直存在着等待消费,。

2、运行消费者

       接下来我们就来启动项目,消息就会被自然消费掉,然后一有消息就进行消费,消费完了之后继续等待。

也可以查看控制台,成功拿到了之前被生产的那条消息。证明消费成功了。

       接下来我们在保持项目启动的状态下,我们再运行一下生产测试类,往队列里再发送一条消息,看看消息会不会被被立马消费?

查看Server端,很明显,消息一瞬间就被消费了,Ready = 0,则线图也有波动。

最明显的就是看你的控制台,看看消费者是否执行有消息打印。

       ... ...

       ok,以上就是我这期的全部内容啦,如果还想学习更多,你可以看看我的往期热文推荐哦,每天积累一个奇淫小知识,日积月累下去,你一定能成为令人敬仰的大佬的。好啦,咱们下期见~

六、往期热门推荐

文末🔥

如果还想要学习更多,小伙伴们可关注bug菌专门为大家创建的专栏《springboot零基础入门教学》,从无到有,从零到一!希望能帮助到更多小伙伴们。

我是bug菌,一名想走👣出大山改变命运的程序猿。接下来的路还很长,都等待着我们去突破、去挑战。来吧,小伙伴们,我们一起加油!未来皆可期,fighting!

感谢认真读完我博客的铁子萌,在这里呢送给大家一句话,不管你是在职还是在读,绝对终身受用。
时刻警醒自己:
抱怨没有用,一切靠自己;
想要过更好的生活,那就要逼着自己变的更强,生活加油!!!