RabbitMQ快速入门和使用

news2024/11/15 12:02:12

文章目录

  • 1. 基础理论
    • 1.1. 同步调用与异步调用
    • 1.2. RabbitMQ 安装与运行
      • 1.2.1. 常见消息模型
  • 2. 基本消息队列的应用
    • 2.1. 消息发送流程
    • 2.2. 消息接收流程
  • 3. SpringAMQP的基础理论与应用(想快速应用看这里)
    • 3.1. 基础理论
    • 3.2. 【案例一】实现HelloWorld中的基础消息队列功能
    • 3.3. 【案例二】 Work Queue 工作队列
    • 3.4. 发布订阅模式
      • 3.4.1. 【案例三】广播(Fanout)
      • 3.4.2. 【案例四】路由(Direct)
      • 3.4.3. 【案例五】主题(Topic)
    • 3.5 消息转换器

1. 基础理论

1.1. 同步调用与异步调用

同步调用

  • 优点:时效性强,可以立即得到结果
  • 问题:
    • 耦合度高:每次加入新的需求,都要修改原来的代码
    • 性能和吞吐能力下降:调用者需要等待服务提供者响应,如果调用链过长则响应时间等于每次调用时间之和
    • 资源浪费,有额外的资源消耗:调用链中的每个服务在等待响应过程中,不能释放请求占用的资源,在高并发场景下会极度浪费系统资源
    • 级联失败:如果服务提供者出现问题,所有调用方都会跟着出问题,迅速导致整个微服务群故障

异步调用
常见实现是事件驱动模式

  • 优势
    • 服务解耦
    • 性能提升,吞吐量提高
    • 服务没有强依赖,不担心级联失败问题
    • 流量削峰
  • 缺点
    • 依赖于Broker的可靠性、安全性、吞吐能力
    • 架构复杂了,业务没有明显的流程线,不好追踪管理

1.2. RabbitMQ 安装与运行

MQ(MessageQueue):消息队列,存放消息的队列,事件驱动框架中的Broker

RabbitMQ是基于Erlang语言开发的开源消息通信中间件,官网地址:https://www.rabbitmq.com

安装MQ(docker形式)

docker pull rabbitmq:3-management

运行MQ(docker形式)

docker run \
-e RABBITMQ_DEFAULT_USER=用户名 \
-e RABBITMQ_DEFAULT_PASS=密码 \
--name mq \
--hostname mq1 \
-p 15672:15672 \
-p 5672:5672 \
-d \
rabbitmq:3-management

概念
channel:操作MQ的工具
exchange:路由消息到队列中
queue:缓存消息
virtual host:虚拟主机,是对queue、exchange等资源的逻辑分组

在这里插入图片描述

1.2.1. 常见消息模型

① 基本消息队列(BasicQueue)
publisher:消息发布者,将消息发送到队列queue
queue:消息队列,负责接受并缓存消息
consumer:消息订阅者
请添加图片描述

② 工作消息队列(WorkQueue)请添加图片描述

③ 发布订阅(Publish/Subscribe),有根据交换机类型不同分为三种:
Fanout Exchange:广播
请添加图片描述

Direct Exchange:路由
请添加图片描述

Topic Exchange:主题
请添加图片描述

2. 基本消息队列的应用

依赖

<!--AMQP依赖,包含RabbitMQ-->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-amqp</artifactId>
</dependency>

2.1. 消息发送流程

1.简历connection
2.创建channel
3.利用channel声明队列
4.利用channel向队列发送消息

代码

    @Test
    public void testSendMessage() throws IOException, TimeoutException {
        // 1.建立连接
        ConnectionFactory factory = new ConnectionFactory();
        
        // 1.1.设置连接参数,分别是:主机名、端口号、vhost、用户名、密码
        factory.setHost("");//ip
        factory.setPort(5672);
        factory.setVirtualHost("/");
        factory.setUsername("");//账号
        factory.setPassword("");//密码
        
        // 1.2.建立连接
        Connection connection = factory.newConnection();
        
        // 2.创建通道Channel
        Channel channel = connection.createChannel();
        
        // 3.创建队列
        String queueName = "simple.queue";
        channel.queueDeclare(queueName, false, false, false, null);
        
        // 4.发送消息
        String message = "hello, rabbitmq!";
        channel.basicPublish("", queueName, null, message.getBytes());
        System.out.println("发送消息成功:【" + message + "】");
        
        // 5.关闭通道和连接
        channel.close();
        connection.close();
    }

2.2. 消息接收流程

1.简历connection
2.创建channel
3.利用channel声明队列
4.定义consumer的消费行为handleDelivery
5.利用channel将消费者与队列绑定

代码

    public static void main(String[] args) throws IOException, TimeoutException {
        // 1.建立连接
        ConnectionFactory factory = new ConnectionFactory();
        // 1.1.设置连接参数,分别是:主机名、端口号、vhost、用户名、密码
        factory.setHost("");//ip
        factory.setPort(5672);
        factory.setVirtualHost("/");
        factory.setUsername("");//账号
        factory.setPassword("");//密码
        // 1.2.建立连接
        Connection connection = factory.newConnection();

        // 2.创建通道Channel
        Channel channel = connection.createChannel();

        // 3.创建队列
        String queueName = "simple.queue";
        channel.queueDeclare(queueName, false, false, false, null);

        // 4.订阅消息
        channel.basicConsume(queueName, true, new DefaultConsumer(channel){
            @Override
            public void handleDelivery(String consumerTag, Envelope envelope,
                                       AMQP.BasicProperties properties, byte[] body) throws IOException {
                // 5.处理消息
                String message = new String(body);
                System.out.println("接收到消息:【" + message + "】");
            }
        });
        System.out.println("等待接收消息。。。。");
    }

3. SpringAMQP的基础理论与应用(想快速应用看这里)

官方地址:https://spring.io/projects/spring-amqp

3.1. 基础理论

AMQP(Advanced Message Queuing Protocol):高级消息队列协议,是用于在应用程序或之间传递业务消息的开放标准。该协议与语言和平台无关,更服务微服务中独立型的要求。

Spring AMQP:是基于AMQP协议定义的一套API规范,提供了模板来发送和接收消息。包含两个部分,其中spring-amqp是抽象基础,spring-rabbit是底层的默认实现。

Spring AMQP 特点
① 侦听器容器,用于异步处理入站消息
② 用于发送和接收消息的RabbitTemplate
③ RabbitAdmin用于自动声明队列,交换和绑定

3.2. 【案例一】实现HelloWorld中的基础消息队列功能

请添加图片描述
流程:
① 在父工程中引入spring-amqp的依赖

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-amqp</artifactId>
</dependency>

② 在application.yml中配置rabbitmq的信息

spring:
  rabbitmq:
    host: ip
    port: 5672
    virtual-host: /
    username: 账号
    password: 密码

③ 在publisher服务中利用RabbitTemplate发送消息到simple.queue队列

@RunWith(SpringRunner.class)
@SpringBootTest
public class PublisherTest {

	@Autowired
    private RabbitTemplate rabbitTemplate;

    @Test
    public void testSimpleQueue(){
        String queueName = "simple.queue";
        String message = "hello, spring amqp";
        rabbitTemplate.convertAndSend(queueName,message);
    }
}

④ 在consumer服务中编写消费逻辑,绑定simple.queue队列

@Component
public class SpringRabbitListener {
    
    //@RabbitListener(queues = "simple.queue")
    @RabbitListener(queuesToDeclare = { @Queue("simple.queue")})//如果队列不存在就创建队列
    public void listenSimpleQueueMessage(String msg)throws InterruptedException{
        System.out.println("spring 消费者接收到消息:【"+msg+"】");
    }
   
}

3.3. 【案例二】 Work Queue 工作队列

Work Queue,工作队列,可以提高消息处理速度,避免消息堆积
请添加图片描述

流程:
① 在 publisher 服务中定义测试方法,每秒产生50条消息,发送至simple.queue

	@Autowired
    private RabbitTemplate rabbitTemplate;
    @Test
    public void testWorkQueue() throws Exception{
        String queueName = "simple.queue";
        String message = "hello, spring amqp";
        for (int i=0;i<50;i++){
            rabbitTemplate.convertAndSend(queueName,message+i);
            Thread.sleep(20);
        }
    }

② 在 consumer 服务中定义两个消息监听者,都监听simple.queue
③ 消费者1每秒处理50条数据,消费者2每秒处理5条数据

@Component
public class SpringRabbitListener {

    @RabbitListener(queuesToDeclare = { @Queue("simple.queue")})
    public void listenWorkQueueMessage(String msg)throws InterruptedException{
        System.out.println("spring 消费者【1】接收到消息:【"+msg+"】" + LocalTime.now());
        Thread.sleep(20);
    }
    @RabbitListener(queuesToDeclare = { @Queue("simple.queue")})
    public void listenWorkQueueMessage2(String msg)throws InterruptedException{
        System.out.println("spring 消费者【2】接收到消息:【"+msg+"】" + LocalTime.now());
        Thread.sleep(200);
    }
}

④ 因为存在消息预取机制,队列中的消息会平均分配给两个队列,修改配置文件,空值预取消息的上限制

spring:
  rabbitmq:
    listener:
      simple:
        prefetch: 1 # 每次只能取一条消息,处理完才能获取下一条消息

3.4. 发布订阅模式

发布订阅模式与之前案例的区别是,允许将同一消息发送给多个消费者,实现方式是加入了exchange(交换机)。
常见交换机类型包括:广播(Fanout)、路由(Direct)、话题(Topic)

3.4.1. 【案例三】广播(Fanout)

Fanout Exchange 会将接收到的消息路由到每一个跟其绑定的queue
请添加图片描述
流程:
① 在 consumer 服务中,创建配置类,声明队列、交换机,并将两者绑定(创建绑定关系)

@Configuration
public class FanoutConfig {
    //声明Fanout交换机
    @Bean
    public FanoutExchange fanoutExchange(){
        return new FanoutExchange("itcast.fanout");
    }
    //声明第一个队列
    @Bean
    public Queue fanoutQueue1(){
        return new Queue("fanout.queue1");
    }
    //绑定队列1和交换机
    @Bean
    public Binding bingingQueue1(Queue fanoutQueue1,FanoutExchange fanoutExchange){
        return BindingBuilder.bind(fanoutQueue1).to(fanoutExchange);
    }
    //声明第二个队列
    @Bean
    public Queue fanoutQueue2(){
        return new Queue("fanout.queue1");
    }
    //绑定队列2和交换机
    @Bean
    public Binding bingingQueue2(Queue fanoutQueue2,FanoutExchange fanoutExchange){
        return BindingBuilder.bind(fanoutQueue2).to(fanoutExchange);
    }
}

② 在 consumer 服务中,编写两个消费者方法,分别监听 fanout.queue1 和 fanout.queue2

@Component
public class SpringRabbitListener {
    @RabbitListener(queues = "fanout.queue1")
    public void listenFanoutQueue1Message(String msg){
        System.out.println("spring 消费者 1 接收到消息:【"+msg+"】");
    }
    @RabbitListener(queues = "fanout.queue2")
    public void listenFanoutQueue2Message(String msg){
        System.out.println("spring 消费者 2 接收到消息:【"+msg+"】");
    }
}

③ 在 publisher 中编写测试方法,向 itcast.fanout交换机发送消息

	@Autowired
    private RabbitTemplate rabbitTemplate;
    @Test
    public void testSendFanoutExchange(){
        //交换机名称
        String exchangeName = "itcast.fanout";
        //消息
        String msg = "hello,every one";
        //发送消息
        rabbitTemplate.convertAndSend(exchangeName,"",msg);
    }

交换机的作用:

① 接收publisher发送的消息
② 将消息按照规则路由到与之绑定的队列
③ 不能缓存消息,路由失败,消息丢失
④ FanoutExchange会将消息路由到每个绑定的队列

3.4.2. 【案例四】路由(Direct)

Direct Exchange会将接收到的消息根据规则路由到指定的Queue。
每一个Queue都与Exchange设置一个BindingKey
发布者发送消息时,指定消息的RoutingKey
Exchange将消息路由到BindingKey与消息RoutingKey一致的队列
请添加图片描述
流程:
① 在consumer 服务中 利用@RabbitListener声明Exchange、Queue、RoutingKey

@Component
public class SpringRabbitListener {

    @RabbitListener(bindings = @QueueBinding(
            value = @Queue(name = "direct.queue1"),
            exchange = @Exchange(name = "itcast.direct",type = ExchangeTypes.DIRECT),
            key = {"red","blue"}
    ))
    public void listenDirectQueue1(String msg){
        System.out.println("spring 消费者 1 接收到 direct.queue1 的消息:【"+msg+"】");
    }
    @RabbitListener(bindings = @QueueBinding(
            value = @Queue(name = "direct.queue2"),
            exchange = @Exchange(name = "itcast.direct",type = ExchangeTypes.DIRECT),
            key = {"red","yellow"}
    ))
    public void listenDirectQueue2(String msg){
        System.out.println("spring 消费者 2 接收到 direct.queue2 的消息:【"+msg+"】");
    }
}

② 在 publish 服务发送消息到DirectExchange

    @Autowired
    private RabbitTemplate rabbitTemplate;

    @Test
    public void testSendDirectExchange(){
        //交换机名称
        String exchangeName = "itcast.direct";
        //消息
        String msg = "hello,blue";
        //routingKey
        String routingKey = "blue";
        //发送消息
        rabbitTemplate.convertAndSend(exchangeName,routingKey,msg);
    }

Direct交换机与Fanout交换机的差异:
Fanout减缓及将消息路由给每一个与之绑定的队列,Direct交换机根据RoutingKey判断路由给哪个队列。如果多个队列具有相同的routingKey,则与Fanout功能类似。

3.4.3. 【案例五】主题(Topic)

Topic Exchange 与 Direct Exchange类似,区别在于routingKey必须是多个单词的列表,并且以.分割。
Queue与Exchange指定BingingKey时可以使用通配符:#代表0或多个单词,*代表一个单词
请添加图片描述

流程:
① 利用 @RabbitListener 声明 Echange、Queue、RoutingKey
② 在 consumer 服务中,编写两个消费者方法,分别监听 topic.queue1 和 topic.queue2

@Component
public class SpringRabbitListener {

    @RabbitListener(bindings = @QueueBinding(
            value = @Queue(name = "topic.queue1"),
            exchange = @Exchange(name = "itcast.topic",type = ExchangeTypes.TOPIC),
            key = "china.#"
    ))
    public void listenTopicQueue1(String msg){
        System.out.println("spring 消费者 1 接收到 topic.queue1 的消息:【"+msg+"】");
    }
    @RabbitListener(bindings = @QueueBinding(
            value = @Queue(name = "topic.queue2"),
            exchange = @Exchange(name = "itcast.topic",type = ExchangeTypes.TOPIC),
            key = "#.news"
    ))
    public void listenTopicQueue2(String msg){
        System.out.println("spring 消费者 2 接收到 topic.queue2 的消息:【"+msg+"】");
    }

③ 在 publisher 中编写测试方法,向 itcast.topic 发送消息

    @Autowired
    private RabbitTemplate rabbitTemplate;
    @Test
    public void testSendTopicExchange(){
        //交换机名称
        String exchangeName = "itcast.topic";
        //消息
        String msg = "天气还行";
        //发送消息
        rabbitTemplate.convertAndSend(exchangeName,"china.weather",msg);
    }

3.5 消息转换器

在 SpringAMQP 的发送方法中,接收消息的类型是Object,也就是说我们可以发送任意对象类型的消息,SpringAMQP会帮我们序列化为字节后发送。

Spring的对消息的处理是由org.springframework.amqp.support.converter.MessageConverter来处理的。而默认实现是SimpleMessageConverter类型的Bean即可。推荐使用JSON方式序列化。

步骤(两端需要):
① 引入依赖

<dependency>
    <groupId>com.fasterxml.jackson.dataformat</groupId>
    <artifactId>jackson-dataformat-xml</artifactId>
    <version>2.11.4</version>
</dependency>

② 声明 MessageConverter

    @Bean
    public MessageConverter jsonMessageConverter(){
        return new Jackson2JsonMessageConverter();
    }

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Neo4j数据库模糊查询

1、Neo4j单个查询条件模糊查询1.1使用 ~’.模糊匹配对象.’ 进行表示1.1.1 查询节点MATCH(n:Author) WHERE n.name ~.*梦.* RETURN n1.1.2 查询关系MATCH p({title:锆石U-Pb和Lu-Hf同位素研究内蒙乌努格吐山斑岩型铜钼矿岩浆岩特征})-[r:has_illustration]->(i:Illustration…

Python应用开发——制作bin文件

Python应用开发——制作bin文件 目录Python应用开发——制作bin文件前言1 环境搭建2 代码编写与测试结束语前言 什么是bin&#xff1f; bin是二进制文件&#xff0c;其用途依系统或应用而定。一种文件格式binary的缩写。一个后缀名为".bin"的文件&#xff0c;只是表…

无代码配置态势感知分析应用,预判你的预判

森林发生火势灾情时&#xff0c;应急管理中心快速做出部署&#xff0c;实时监测并分析演变趋势大型交通事故发生&#xff0c;应急指挥中对前端人员、车辆的远程调度线路规划实时监测无人机对电站电厂的运维工作公安警务对嫌疑人、嫌疑车辆等目标的跟踪侦查……以上这些&#xf…

Acwing---基础算法(一)

文章目录 快速排序归并排序整数二分浮点数二分一、快速排序 #include<iostream>using namespace std;const int N 1e6 10;int n; int q[N];void quick_sort(int q[], int l, int r) {//此时区间只有一个数或者没有数不需要排序了if (l > r) return;int x q[l], i…

【QCA】【实例】高通DTS中添加BLSP设备节点的基本配置

文章目录0. env1. 简介2. 需求及资料2.1 需求2.2 资料3. DTS实际配置及简述0. env IPQ601x SPF11.5cs 1. 简介 BLSP(BAM Low-Speed Peripheral) 不同chip有不止一组的BLSP&#xff0c;每个BLSP又有多个端口供使用。 每个端口功能可以复用为&#xff1a;SPI 或者 I2CUART 2. 需求…

计算机网络知识详解之:TCP连接原理详解

网络知识详解之&#xff1a;TCP连接原理详解 文章目录网络知识详解之&#xff1a;TCP连接原理详解TCP连接三次握手一、准备工作二、一次握手三、二次握手四、三次握手为什么TCP客户端最后还要发送一次确认呢&#xff1f;为什么要3次握手?握手中的SYN超时重试TCP协议缺陷四次挥…

HECS 安装mqtt

下载(hecs &#xff0c;centos8的样子&#xff0c;对mosquitto 版本高了安装不了)wget https://mosquitto.org/files/source/mosquitto-1.5.9.tar.gztar -zxvf mosquitto-1.5.9.tar.gz安装前置工具yum install gcc-cyum install cmakeyum install openssl-devel编译cd mosquitt…

Vue项目启动后跳转到制定路由页面

前言 今天把自己的项目布局完成了&#xff0c;但是想在项目启动的时候默认跳转到登录页面。 这其实需要借助路由实现跳转 开始编写之前&#xff0c;大家可以看下我的布局&#xff1a; 安装并使用路由 关于如何安装并使用路由&#xff0c;可以参考&#xff1a;Vue安装并使用路…

LeetCode_单周赛_330

6337. 统计桌面上的不同数字 代码 后面出现的数字都是小于 n 的。 n 1 时&#xff0c;答案是 1。 n > 1时&#xff1a; 第一天&#xff0c;n % (n - 1) 1&#xff0c;n - 1会被加入第二天&#xff0c;(n - 1) % (n - 2) 1&#xff0c;n - 2 被加入 递推&#xff0c;一…

Java 8 Optional 介绍

1. 前言 空指针确实会产生很多问题&#xff0c;我们经常遇到空的引用&#xff0c;然后又想从这个空的引用上去获取其他的值&#xff0c;接着理所当然的碰到了 NullPointException。这是你可能会想&#xff0c;这报错很好处理&#xff0c;然后你看了眼报错行数&#xff0c;对比了…

聚合函数学习

文章目录聚合函数介绍理解类型语法AVG和SUMMIN和MAX函数COUNT函数GROUP BY基本使用使用多个列分组GROUP BY中使用WITH ROLLUPHAVING基本使用WHERE和HAVING的对比SELECT执行顺序查询结构SELECT执行顺序SQL 的执行原理聚合函数介绍 理解 聚合&#xff08;或聚集、分组&#xff…

java集合类-Map

Map-增强的Map集合 Map用于保存具有映射关系的数据&#xff0c;因此Map集合里保存着两组值&#xff0c;一组值用于保存Map里的key&#xff0c;另外一组值用于保存Map里的value&#xff0c;key和value都可以是任何引用类型的数据。Map的key不允许重复&#xff0c;即同一个Map对象…

【Linux】TCP三次握手,四次挥手原理

今天在书中找到了比较详细的解释&#xff0c;记录一下 三次握手 在可以使用TCP链路之前&#xff0c;必须在客户端和主机之间显式建立连接。如上所述&#xff0c;在主动&#xff08;active&#xff09;和被动&#xff08;passive&#xff09;连接的建立方式是有区别的。 内核…

生鲜巨变:每日优鲜、叮咚买菜、盒马“分道扬镳”?

此前&#xff0c;在疫情影响下&#xff0c;人们出门购物频次减少&#xff0c;传统买菜模式也受到了一定的冲击。在此背景下&#xff0c;既能够解决人们买菜难题又能够减少人与人接触的生鲜电商&#xff0c;赢得了众多消费者的青睐。而随着大量用户涌入其中&#xff0c;整个生鲜…

【GD32F427开发板试用】硬件IIC读取SHT40温湿度传感器

本篇文章来自极术社区与兆易创新组织的GD32F427开发板评测活动&#xff0c;更多开发板试用活动请关注极术社区网站。作者&#xff1a;烟花易冷 介绍 很荣幸又能再次的参加技术社区的开发板试用活动&#xff0c;此次参加用的是GD32F427系列的芯片&#xff0c;该芯片相较于GDF31…

OpenPPL PPQ量化:原理与实践

目录 量化原理 为什么需要量化&#xff1f; 量化粒度 框架综述 算子划分 量化中的图融合操作 量化实践&#xff1a;以pytorch mobilenet v2 模型为例 源码阅读 torch模型和onnx量化过程中的区别 后记 量化原理 为什么需要量化&#xff1f; 1、减少内存带宽和存储空…

C++Morris遍历

一、关于Morris算法 简介 Morris算法是针对二叉树实现的一个遍历算法&#xff0c;它是一种空间复杂度为O(1)的遍历算法 通常情况下使用迭代或递归的方式遍历二叉树的空间开销都是O(N)级别的&#xff0c;较为理想的情况下可以做到O(logn)级别&#xff0c;而Morris算法通过更改…

Windows Kerberos客户端配置并访问CDH

安装 Kerberos 客户端 配置 hosts 1、配置集群 hosts 到 Windows&#xff08;C:\Windows\System32\drivers\etc\hosts&#xff09;&#xff1b; 2、调整windows环境变量&#xff0c;将系统环境变量 PATH 中的 C:\Program Files\MIT\Kerberos\bin 放置在最前边&#xff0c;建…

目标跟踪心得篇五:MOT数据集标注、DarkLabel不能自动跟踪解决方案

跟踪方向的标注成本非常很大的 ,那么我们如何尽可能一次性弄好呢? 所选标注工具:DarkLabel DarkLabel是一个轻量的视频标注软件,尤其做MOT任务非常友好,其标注可以通过脚本转化为标准的目标检测数据集格式、ReID数据集格式和MOT数据集格式。 使用之前: darklabel.yml:保…

Python国际化学习教程

很幸运python提供了中文等其他语言的教程&#xff01; 这里以13.11.1为例 Python 是一门易于学习、功能强大的编程语言。它提供了高效的高级数据结构&#xff0c;还能简单有效地面向对象编程。Python 优雅的语法和动态类型以及解释型语言的本质&#xff0c;使它成为多数平台上写…