RabbitMQ是一个广泛使用的开源消息代理软件,它实现了高级消息队列协议(AMQP)。RabbitMQ支持多种消息传递模式,其中最基本的是点对点(Point-to-Point)通讯方式。在这种模式下,消息生产者将消息发送到一个队列,而消息消费者从该队列中接收消息。每个消息只会被一个消费者消费一次。
下面将通过一个简单的Java代码案例,详细介绍如何在RabbitMQ中实现点对点通讯。
1. 原理分析
- 一个生产者,一个默认的交换机,一个队列,一个消费者
- 看起来是生产者直接发送到队列,实际上是发送到了默认交换机
结构图:
2. 环境准备
在开始之前,请确保你已经安装了以下环境:
- Java Development Kit (JDK) 8 或更高版本
- Apache Maven
- RabbitMQ 服务器
你可以通过以下命令检查Java和Maven的安装情况:
bash
java -version
mvn -version
3. 添加RabbitMQ依赖
首先,我们需要在Maven项目中添加RabbitMQ的Java客户端依赖。在你的pom.xml
文件中添加以下内容:
xml
<dependencies>
<dependency>
<groupId>com.rabbitmq</groupId>
<artifactId>amqp-client</artifactId>
<version>5.20.0</version>
</dependency>
</dependencies>
4. 创建消息生产者
接下来,我们创建一个消息生产者,它将消息发送到RabbitMQ的队列中。
java
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;
public class MessageProducer {
private final static String QUEUE_NAME = "hello";
public static void main(String[] argv) throws Exception {
// 创建连接工厂
ConnectionFactory factory = new ConnectionFactory();
factory.setHost("192.168.200.138");
factory.setPort(5672);
factory.setVirtualHost("/test");
factory.setUsername("test");
factory.setPassword("test");
// 创建连接和通道
try (Connection connection = factory.newConnection();
Channel channel = connection.createChannel()) {
// 声明队列
channel.queueDeclare(QUEUE_NAME, false, false, false, null);
// 发送消息
String message = "Hello World!aaa";
// 发布消息到exchange,同时指定路由的规则
// 参数1:指定exchange,使用""。代表默认交换机
// 参数2:指定路由的规则,使用具体的队列名称。
// 参数3:指定传递的消息所携带的properties,使用null。
// 参数4:指定发布的具体消息,byte[]类型
channel.basicPublish("", QUEUE_NAME, null, message.getBytes());
// Ps:exchange是不会帮你将消息持久化到本地的,Queue才会帮你持久化消息。
System.out.println(" [x] Sent '" + message + "'");
}
}
}
代码解析:
- ConnectionFactory: 用于创建到RabbitMQ服务器的连接。
- Connection: 代表与RabbitMQ服务器的物理连接。
- Channel: 用于发送和接收消息的通道。
- queueDeclare: 声明一个队列,如果队列不存在,则会创建它。
- basicPublish: 将消息发送到指定的队列。
默认交换机上可以看到生产者发送的消息:
5. 创建消息消费者
接下来,我们创建一个消息消费者,它将从RabbitMQ的队列中接收消息。
java
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;
import com.rabbitmq.client.DeliverCallback;
public class MessageConsumer {
private final static String QUEUE_NAME = "hello";
public static void main(String[] argv) throws Exception {
// 创建连接工厂
ConnectionFactory factory = new ConnectionFactory();
factory.setHost("192.168.200.138");
factory.setPort(5672);
factory.setVirtualHost("/test");
factory.setUsername("test");
factory.setPassword("test");
// 创建连接和通道
Connection connection = factory.newConnection();
Channel channel = connection.createChannel();
// 声明队列
//参数1:queue - 指定队列的名称
//参数2:durable - 当前队列是否需要持久化(true)
//参数3:exclusive:是否排外的,有两个作用:
// 一:当连接关闭时connection.close()该队列是否会自动删除;
// 二:该队列是否是私有的private,如果不是排外的,可以使用两个消费者都访问同一个队列,没有任何问题,
// 如果是排外的,会对当前队列加锁,其他通道channel是不能访问的,如果强制访问会报异常:
// com.rabbitmq.client.ShutdownSignalException: channel error; protocol method: #method<channel.close>(reply-code=405, reply-text=RESOURCE_LOCKED - cannot obtain exclusive access to locked queue 'queue_name' in vhost '/', class-id=50, method-id=20)
// 一般等于true的话用于一个队列只能有一个消费者来消费的场景
//参数4:autoDelete - 如果这个队列没有消费者在消费,并且所有消息都消费完,队列自动删除
//参数5:arguments - 指定当前队列的其他信息
channel.queueDeclare(QUEUE_NAME, false, false, false, null);
System.out.println(" [*] Waiting for messages. To exit press CTRL+C");
// 设置消息回调
DeliverCallback deliverCallback = (consumerTag, delivery) -> {
String message = new String(delivery.getBody(), "UTF-8");
System.out.println(" [x] Received '" + message + "'");
};
// 开始消费消息
channel.basicConsume(QUEUE_NAME, true, deliverCallback, consumerTag -> { });
}
}
代码解析:
- DeliverCallback: 用于处理接收到的消息的回调函数。
- basicConsume: 开始消费队列中的消息。
6. 运行代码
- 首先启动RabbitMQ服务器。
- 运行
MessageProducer
类,发送消息。 - 运行
MessageConsumer
类,接收消息。
你应该会看到类似以下的输出:
Producer Output:
[x] Sent 'Hello World!'
Consumer Output:
[*] Waiting for messages. To exit press CTRL+C
[x] Received 'Hello World!'
7. 总结
通过以上步骤,我们成功地在RabbitMQ中实现了点对点通讯。消息生产者将消息发送到队列,而消息消费者从队列中接收消息。这种模式非常适合需要确保消息只被一个消费者处理一次的场景。