RabbitMQ 入门示例(简单模式示例)及 AMQP 相关概念
总结自:BV15k4y1k7Ep
RabbitMQ 相关概念及简述中简单介绍了 RabbitMQ 提供的 6 种工作模式。下面以简单模式为例,介绍 RabbitMQ 的使用。
首先参考 CentOS7 安装及配置 RabbitMQ 安装好 RabbitMQ。
模式说明
简单模式如下:
在上图的模型中,有以下概念:
- P:生产者,也就是要发送消息的程序。
- C:消费者:消息的接受者,会一直等待消息到来。
- queue:消息队列,图中红色部分。类似一个邮箱,可以缓存消息;生产者向其中投递消息,消费者从其中取出消息。
新建工程
先新建 Maven 工程 RabbitMQ 作为父工程,在父工程下新建三个子模块:
- common:公共包
- producer:生产者
- consumer:消费者
在三个模块中添加 amqp-client 依赖:
<dependency>
<groupId>com.rabbitmq</groupId>
<artifactId>amqp-client</artifactId>
<version>5.6.0</version>
</dependency>
在 producer 和 consumer 中添加 common 依赖:
<dependency>
<groupId>com.zhangmingge.rabbitmq</groupId>
<artifactId>common</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
编写 common
在 common 中添加用于获取 RabbitMQ Connection 的工具类,获取到 Connection 之后,后面 producer 和 consumer 才能够往消息队列中投递或接收消息:
package com.zhangmingge.rabbitmq;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;
public class ConnectionUtil {
public static Connection getConnection() throws Exception {
// 创建连接工厂
ConnectionFactory connectionFactory = new ConnectionFactory();
// 主机地址,默认为 localhost
connectionFactory.setHost("192.168.88.128");
// 连接端口,默认为 5672
connectionFactory.setPort(5672);
// 虚拟主机名称,默认为 /
connectionFactory.setVirtualHost("/vhost");
// 连接用户名,默认为 guest
connectionFactory.setUsername("admin");
// 连接密码,默认为 guest
connectionFactory.setPassword("123456");
// 创建连接
return connectionFactory.newConnection();
}
}
注意上面的setVirtualHost
方法,其作用是设置虚拟主机。上面的代码假定admin
用户已经创建了一个名称为/vhost
的虚拟主机。
每一个 RabbitMQ 服务器都能创建虚拟消息服务器,我们称之为虚拟主机。每一个 vhost 本质上是一个 mini 版的 RabbitMQ 服务器,拥有自己的交换机、队列、绑定(先不深究这些概念)等,拥有自己的权限机制。vhost 之于 Rabbit 就像虚拟机之于物理机一样。他们通过在各个实例间提供逻辑上分离,允许为不同的应用程序安全保密的运行数据,这很有用,它既能将同一个 Rabbit 的众多客户区分开来,又可以避免队列和交换器的命名冲突。RabbitMQ 提供了开箱即用的默认的虚拟主机
/
,如果不需要多个 vhost 可以直接使用这个默认的 vhost。下图演示如何创建虚拟主机:
编写 producer
简单模式发送消息:
- 获取连接
- 创建频道
- 声明(创建)队列
- 发送信息
- 关闭资源
信道/频道(Channel)和连接(Connection):Channel 是物理 TCP 连接中的虚拟连接。当应用通过 Connection 与云消息队列 RabbitMQ 版建立连接后,所有的 AMQP 协议操作(例如创建队列、发送消息、接收消息等)都会通过 Connection 中的 Channel 完成。Channel 可以复用 Connection,即一个 Connection 下可以建立多个 Channel。Channel 不能脱离 Connection 独立存在,而必须存活在 Connection 中。当某个 Connection 断开时,该 Connection 下的所有 Channel 都会断开。当大量应用需要与云消息队列 RabbitMQ 版建立多个连接时,使用 Channel 来复用 Connection,可以减少网络资源和 RabbitMQ 资源消耗。
package com.zhangmingge.rabbitmq.simple;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
public class Producer {
static final String QUEUE_NAME = "simple_queue";
public static void main(String[] args) throws Exception {
// 创建连接
Connection connection = ConnectionUtil.getConnection();
// 创建频道
Channel channel = connection.createChannel();
// 声明(创建)队列
/*
* 参数 1:队列名称
* 参数 2:是否定义持久化队列
* 参数 3:是否独占本次连接
* 参数 4:是否在不使用的时候自动删除队列
* 参数 5:队列其它参数
*/
channel.queueDeclare(QUEUE_NAME, true, false, false, null);
// 要发送的信息
String message = "你好;小兔子!";
/*
* 参数 1:交换机名称,如果没有指定则使用默认 Default Exchange
* 参数 2:路由 key,简单模式可以传递队列名称
* 参数 3:消息其它属性
* 参数 4:消息内容
*/
channel.basicPublish("", QUEUE_NAME, null, message.getBytes());
System.out.println("已发送消息:" + message);
// 关闭资源
channel.close();
connection.close();
}
}
先不管交换机和路由 key 的概念,其他工作模式中会重点介绍。
在执行上述的消息发送之后,登录 RabbitMQ 的管理控制台,可以发现队列和其中的消息:
编写 consumer
下面编写消费者消费上面的消息:
- 获取连接
- 创建频道
- 声明(创建)队列
- 创建消费者,并编写消费逻辑
- 监听消息
package com.zhangmingge.rabbitmq.simple;
import com.rabbitmq.client.*;
import java.io.IOException;
public class Consumer {
public static void main(String[] args) throws Exception {
Connection connection = ConnectionUtil.getConnection();
// 创建频道
Channel channel = connection.createChannel();
// 声明(创建)队列
/*
* 参数 1:队列名称
* 参数 2:是否定义持久化队列
* 参数 3:是否独占本次连接
* 参数 4:是否在不使用的时候自动删除队列
* 参数 5:队列其它参数
*/
channel.queueDeclare(Producer.QUEUE_NAME, true, false, false, null);
// 创建消费者:并设置消息处理
DefaultConsumer consumer = new DefaultConsumer(channel) {
@Override
/*
* consumerTag 消息者标签,在 channel.basicConsume 时候可以指定
* envelope 消息包的内容,可从中获取消息 id,消息 routingKey,交换机,消息和重传标志 (收到消息失败后是否需要重新发送)
* properties 属性信息
* body 消息
*/
public void handleDelivery(String consumerTag,
Envelope envelope,
AMQP.BasicProperties properties,
byte[] body) throws IOException {
// 路由 key
System.out.println("路由 key 为:" + envelope.getRoutingKey());
// 交换机
System.out.println("交换机为:" + envelope.getExchange());
// 消息 id
System.out.println("消息 id 为:" + envelope.getDeliveryTag());
// 收到的消息
System.out.println("接收到的消息为:" + new String(body, "utf-8"));
}
};
// 监听消息
/*
* 参数 1:队列名称
* 参数 2:是否自动确认,设置为 true 为表示消息接收到自动向 mq 回复接收到了,mq 接收到回复会删除消息,设置为 false 则需要手动确认
* 参数 3:消息接收到后回调
*/
channel.basicConsume(Producer.QUEUE_NAME, true, consumer);
// 不关闭资源,应该一直监听消息
// channel.close();
// connection.close();
}
}
运行 consumer 后,可以看到 consumer 打印的日志消息,每运行一次 producer,consumer 就会对应打印一次消息。
AMQP 相关概念
了解了上面的示例之后,回头看看 AMQP 中的一些概念。
AMQP 是一个提供统一消息服务的应用层标准高级消息队列协议,是应用层协议的一个开放标准,为面向消息的中间件设计。
RabbitMQ 是 AMQP 协议的 Erlang 的实现。
概念 | 说明 |
---|---|
连接 Connection | 一个网络连接,比如 TCP/IP 套接字连接。 |
会话 Session | 端点之间的命名对话。在一个会话上下文中,保证“恰好传递一次”。 |
信道/频道 Channel | 多路复用连接中的一条独立的双向数据流通道。为会话提供物理传输介质。 |
客户端 Client | AMQP 连接或者会话的发起者。AMQP 是非对称的,客户端生产和消费消息,服务器存储和路由这些消息。 |
服务节点 Broker | 消息中间件的服务节点。一般情况下可以将一个 RabbitMQ Broker 看作一台 RabbitMQ 服务器。 |
端点 Endpoint | AMQP 对话的任意一方。一个 AMQP 连接包括两个端点(一个是客户端,一个是服务器)。 |
消费者 Consumer | 一个从消息队列里请求消息的客户端程序。 |
生产者 Producer | 一个向交换机发布消息的客户端应用程序。 |
参考: