RabbitMQ工作流程

上篇文章:

RabbitMQ的介绍与安装https://blog.csdn.net/sniper_fandc/article/details/149310501?fromshare=blogdetail&sharetype=blogdetail&sharerId=149310501&sharerefer=PC&sharesource=sniper_fandc&sharefrom=from_link

目录

[1 AMQP协议](#1 AMQP协议)

[2 工作流程](#2 工作流程)

[3 流程演示](#3 流程演示)

[3.1 引入依赖](#3.1 引入依赖)

[3.2 生产者](#3.2 生产者)

[3.3 消费者](#3.3 消费者)


1 AMQP协议

AMQP(Advanced Message Queuing Protocol)协议是一种高级消息队列协议,它定义了消息交换功能 ,包含****交换机(Exchange)和队列(Queue)****组件,生产者的消息首先传输到交换机,由交换机进行路由分发到指定的队列中并等待消费者接收。

除此以外,它还定义了网络通信的协议,允许生产者和消费者遵循该协议和消息代理来与实现了AMQP协议的模型进行通信。

因此,RabbitMQ就是实现了AMQP协议的一种产品,其内部结构也包含交换机和队列。

2 工作流程

RabbitMQ遵循生产者消费者模型,由生产者Producer生产消息,RabbitMQ作为消息中间件暂时存储消息到队列中,消费者Consumer从队列中获取消息(不需要知道是谁生产的)。同时,生产者和消费者也是RabbitMQ的客户端。

**Connection:**Producer和RabbitMQ、Consumer和RabbitMQ基于TCP来建立连接,一个连接包含多个通道channel(逻辑上各通道之间相互独立,用于实现连接复用,减少频繁建立/关闭TCP连接的开销),发送消息和接收消息都是基于channel。

**Virtual Host:**逻辑上相互独立的虚拟机,不同于安装不同系统的那个虚拟机。类似于MySQL的多个databases,各个database相互隔离,提供不同的数据存储服务给不同的业务。Virtual Host也是相互隔离,提供不同的消息交换服务给不同的用户(使用方)。

**Exchange:**交换机,生产者的消息进入RabbitMQ后首先进入Exchange,由Exchange进行路由分发(根据消息类型、规则和标签等等),把消息分发给指定的Queue。如果找不到Queue,就会丢弃消息/返回给生产者(根据生产者配置策略)。

**Queue:**队列,存储消息。Queue和Consumer之间是多对多关系,即一个Queue可以被多个Consumer订阅;一个Consumer可以订阅多个不同的Queue。

完整的流程:

1.Producer生产了一条消息(通常带有标签来方便路由);

2.Producer和RabbitMQ建立Connection并开启一个通道channel;

3.Producer声明Exchange和Queue分别是谁;

4.Producer发送消息给RabbitMQ;

5.Exchange根据消息类型、标签等信息把消息路由给Queue;

6.Consumer根据订阅的Queue以及消息推送的不同策略来消费消息。

3 流程演示

3.1 引入依赖

XML 复制代码
        <dependency>

            <groupId>com.rabbitmq</groupId>

            <artifactId>amqp-client</artifactId>

            <version>5.20.0</version>

        </dependency>

3.2 生产者

java 复制代码
import com.rabbitmq.client.Channel;

import com.rabbitmq.client.Connection;

import com.rabbitmq.client.ConnectionFactory;



public class RabbitProducer {

    public static void main(String[] args) throws Exception {

        //1.创建连接工厂

        ConnectionFactory factory = new ConnectionFactory();

        //2.设置参数

        factory.setHost("192.168.217.150");//ip

        factory.setPort(5672); //端口号

        factory.setVirtualHost("testVirtual");//虚拟机名称,默认为/

        factory.setUsername("admin");//user,默认guest

        factory.setPassword("admin");//password,默认guest

        //3.创建连接Connection

        Connection connection = factory.newConnection();

        //4.创建channel通道

        Channel channel = connection.createChannel();

        //5.声明队列

         /*

         queueDeclare(String queue, boolean durable, boolean exclusive,

                boolean autoDelete, Map<String, Object> arguments)

         1.queue:队列名称

         2.durable:是否持久化

         3.exclusive:是否独占,只能有一个消费者监听队列,当Connection关闭时,是否删除队列

         4.autoDelete: 是否自动删除,当没有Consumer时,自动删除掉

         5.arguments: 一些其它参数

         */

        //如果没有队列,会自动创建,如果有,则不创建

        channel.queueDeclare("queue1", true, false, false, null);

        //6. 通过channel发送消息到队列中

         /*

         basicPublish(String exchange, String routingKey, AMQP.BasicProperties

                props, byte[] body)

         1.exchange:交换机名称,简单模式下,交换机会使用默认的""

         2.routingKey:路由名称,就是路由到哪个队列

         3.props:配置信息

         4.body:消息内容

         */

        String msg = "Hello RabbitMQ";

        //使用的是内置交换机,使用内置交换机时,routingKey要和队列名称⼀样,才可以路由到对应的队列上去

        channel.basicPublish("", "queue1", null, msg.getBytes());

        //7.释放资源

        System.out.println(msg + "消息发送成功");

        channel.close();

        connection.close();

    }

}

3.3 消费者

java 复制代码
import com.rabbitmq.client.*;

import java.io.IOException;

import java.util.concurrent.TimeUnit;



public class RabbitmqConsumer {

    public static void main(String[] args) throws Exception {

        //1.创建连接工厂

        ConnectionFactory factory = new ConnectionFactory();

        //2.设置参数

        factory.setHost("192.168.217.150");//ip

        factory.setPort(5672); //端口号

        factory.setVirtualHost("testVirtual");//虚拟机名称,默认为/

        factory.setUsername("admin");//user,默认guest

        factory.setPassword("admin");//password,默认guest

        //3.创建连接Connection

        Connection connection = factory.newConnection();

        //4. 创建channel通道

        Channel channel = connection.createChannel();

        //5. 声明队列

         /*

         queueDeclare(String queue, boolean durable, boolean exclusive,

                boolean autoDelete, Map<String, Object> arguments)

         1.queue:队列名称

         2.durable:是否持久化

         3.exclusive:是否独占,只能有一个消费者监听队列,当Connection关闭时,是否删除队列

         4.autoDelete: 是否自动删除,当没有Consumer时,自动删除掉

         5.arguments: 一些其它参数

         */

        //如果没有队列,会自动创建,如果有,则不创建

        channel.queueDeclare("queue1", true, false, false, null);

        //6. 接收消息,并消费

         /*

         basicConsume(String queue, boolean autoAck, Consumer callback)

         参数:

         1.queue:队列名称

         2.autoAck:是否自动确认,消费者收到消息之后,自动确认(MQ认为消费者一定收到,内部自动删除消息)/手动确认(消费者手动告诉MQ收到消息)

         3.callback:回调对象(消费者收到消息后需要执行的逻辑)

         */

        // DefaultConsumer是Consumer的接口实现

        DefaultConsumer consumer = new DefaultConsumer(channel) {

            /*

            回调方法:当收到消息后,会自动执行该方法

            1. consumerTag:标识

            2. envelope:获取一些信息比如:交换机、路由key(队列名称)

            3. properties:配置信息

            4. body:数据

            */

            @Override

            public void handleDelivery(String consumerTag, Envelope envelope,

                                       AMQP.BasicProperties properties, byte[] body) throws IOException {

                System.out.println("接收到消息: " + new String(body));

            }

        };

        channel.basicConsume("queue1", true, consumer);

        //等待回调函数执行完毕之后(防止消息没有接收完毕就立即执行关闭),再关闭资源

        TimeUnit.SECONDS.sleep(5);

        //7.释放资源,消费者相当于是一个监听程序,不需要关闭资源

        //注意:顺序不可改变(要么只关闭连接,通道也会关闭;但是如果先关闭连接,通道已经关闭了再调用通道就报错)

         channel.close();

         connection.close();

    }

}

注意:为什么消费者也要声明队列?因为在实际中,生产者和消费者往往是两个不同的系统,双方什么时候运行都不一定一致。消费者如果不声明队列就直接订阅,可能生产者还未声明队列,不存在队列就会报错,因此消费者也需要声明队列。

如果生产者提前运行,并且明确消息队列是什么,消费者也可以不用声明队列。

下篇文章:

RabbitMQ工作模式https://blog.csdn.net/sniper_fandc/article/details/149310903?fromshare=blogdetail&sharetype=blogdetail&sharerId=149310903&sharerefer=PC&sharesource=sniper_fandc&sharefrom=from_link

相关推荐
sniper_fandc15 分钟前
RabbitMQ的介绍与安装
分布式·rabbitmq
许苑向上3 小时前
分布式缓存击穿以及本地击穿解决方案
java·分布式·缓存
EyeDropLyq4 小时前
从 0 到 1 掌握 自研企业级分布式 ID 发号器
分布式·架构
云淡风轻~~6 小时前
从 CSV文件的加载、分区和处理 来理解 Spark RDD
大数据·分布式·spark
Kevinyu_8 小时前
基于redis的分布式锁 lua脚本解决原子性
redis·分布式·lua
黄雪超8 小时前
Kafka——应该选择哪种Kafka?
大数据·分布式·kafka
项目題供诗8 小时前
Hadoop(二)
大数据·hadoop·分布式
武子康10 小时前
Java-74 深入浅出 RPC Dubbo Admin可视化管理 安装使用 源码编译、Docker启动
java·分布式·后端·spring·docker·rpc·dubbo
contact9712 小时前
分布式弹性故障处理框架——Polly(1)
分布式