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

相关推荐
用户83071968408211 小时前
RabbitMQ vs RocketMQ 事务大对决:一个在“裸奔”,一个在“开挂”?
后端·rabbitmq·rocketmq
初次攀爬者2 天前
RabbitMQ的消息模式和高级特性
后端·消息队列·rabbitmq
初次攀爬者4 天前
ZooKeeper 实现分布式锁的两种方式
分布式·后端·zookeeper
让我上个超影吧5 天前
消息队列——RabbitMQ(高级)
java·rabbitmq
塔中妖5 天前
Windows 安装 RabbitMQ 详细教程(含 Erlang 环境配置)
windows·rabbitmq·erlang
断手当码农5 天前
Redis 实现分布式锁的三种方式
数据库·redis·分布式
初次攀爬者5 天前
Redis分布式锁实现的三种方式-基于setnx,lua脚本和Redisson
redis·分布式·后端
业精于勤_荒于稀5 天前
物流订单系统99.99%可用性全链路容灾体系落地操作手册
分布式
Ronin3055 天前
信道管理模块和异步线程模块
开发语言·c++·rabbitmq·异步线程·信道管理
Asher05095 天前
Hadoop核心技术与实战指南
大数据·hadoop·分布式