[RabbitMQ][官方文档翻译]Hello World
介绍
RabbitMQ是一个消息中介。它能接收和推送消息。可以将它想象成一个邮局。当你往邮箱中放入你的邮件时,你可以确定邮递员最终会将邮件递送给收件人。RabbitMQ就是邮箱、邮局和邮递员。
RabbitMQ和邮局的主要区别在于它处理的不是纸张。它接收、存储、推送的是二进制数据消息。
RabbitMQ和一般的消息传递使用一些专业术语:
- 生产无非就是发送,发送消息的程序就是生产者:
- 队列就是RabbitMQ里的邮箱。尽管消息会在RabbitMQ和您的应用程序之间流通,但是它们只能被存储在队列中。一个队列只会受到主机的内存和磁盘的限制。它显然是一个巨大的消息缓冲器。多个生产者可以给同一个队列发送消息,多个消费者也可以从同一个队列中获取消息。我们用以下图案表示队列:
- 消费就是获取消息。消费者是一个主要等待接收信息的程序:
请注意!生产者producer、消费者和中介broker不必驻留在同一台主机上:相反的,大多数应用程序都不如此。一个应用程序也可以同时是生产者和消费者。
在这一部分教程中,我们将编写两个Java程序:一个发送单条消息的生产者,一个接收消息并打印出来的消费者。我们将忽略Java API中的一些细节,专注于完成这个非常简单的事情。
在以下图解中,P表示生产者,C表示消费者,中间的盒子是一个队列——RabbitMQ代表消费者保存数据的一个消息缓冲。
Java客户端库
RabbitMQ遵从多种协议。这一教程使用AMQP 0-9-1协议。AMQP 0-9-1是一种开源的、原生支持消息传递的协议。RabbitMQ支持多种开发语言。我们将使用RabbitMQ提供的Java客户端。
下载客户端库和它的依赖 (SLF4J API and SLF4J Simple).复制这些文件放到工作文件夹中,以及教程中的Java文件。
请注意!SLF4J Simple对于教程来说足够用了,但是在实际生产中,应该使用完整的日志库,例如Logback。
RabbitMQ也提供了Maven中心仓,groupId是com.rabbitmq,artifactId是 amqp-client。
现在我们已经有了Java客户端和对应依赖,我们可以编写一些代码了。
发送
我们称消息发布者(发送者)为 Send,消息消费者(消费者)为Recv。发布者会连接到RabbitMQ、发送一条消息、然后退出。
在Send.java中,
#我们需要引入一些类:
import com.rabbitmq.client.ConnectionFactory;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.Channel;
#设置类和给队列命名:
public class Send{
private final static String QUEUE_NAME = "hello";
public static void main(String[] argv) throws Exception {
...
}
}
#然后我们便可以创建服务器连接了:
Connection Factory factory = new ConnectionFactory();
factory.setHost("localhost");
try(Connection connection = factory.newConnection();
Channel channel = connection.createChannel()) {
}
这个连接抽象了Socket连接,并为我们处理协议版本协商和身份验证等等。在这里,我们连接到本地机器上的RabbitMQ节点——因此是localhost。如果我们想要连接到另一台机器上的节点,我们只需要在这里简单地指定一下该机器的hostname和ip地址。
接下来我们创建channel。channel可以完成大部分API。注意我们可以使用try-with-resources代码块因为Connection和Channel都实现了java.io.Closeable。这样我们不需要在代码中显式关闭它们。
为了发送消息,我们必须声明一个队列,然后我们可以给该队列发送一条消息。以下均在try-with-resources代码块中:
channel.queueDeclare(QUEUE_NAME, false, false, false, null);
String message = "Hello World!";
channel.basicPublish("", QUEUE_NAME, null, message.getBytes());
System.out.println(" [x] Sent '"+ message + "'");
声明一个队列是幂等的——它只会在队列不存在时创建。消息内容是一个byte数组,所以你可以编码任何你想传输的东西。
https://github.com/rabbitmq/rabbitmq-tutorials/blob/master/java/Send.java
接收
消费者从RabbitMQ中监听消息。所以不像发送者发送一条消息,我们会为了监听消息和打印消息保持消费者运行。
Recv.java代码与Send有相同的引用:
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;
import com.rabbitmq.client.DeliverCallback;
我们将使用额外的DeliverCallback接口来缓冲服务器推送给我们的消息。
设置都与发送者相同。我们创建连接和channel,然后声明一个需要消费的队列。请注意,这与发送者发布到的队列相匹配。
public class Recv{
private final static String QUEUE_NAME = "hello";
public static void main(String[] argv)throws Exception {
ConnectionFactory factory = new ConnectionFactory();
factory.setHost("localhost");
Connection connection = factory.newConnection();
Channel channel = connection.createChannel();
channel.queueDeclare(QUEUE_NAME, false, false, false, null);
System.out.println(" [*] Waiting for messages. To exit press CTRL+C");
}
}
请注意,我们也在这里声明了队列。因为我们可能先于生产者运行消费者。我们需要保证当我们尝试从队列中获取队列时该队列已经存在。
为什么我们不使用try-with-resource代码块来自动关闭channel和连接呢?通过这样做,我们只需让程序继续运行,关闭然后退出!这样就很尴尬了,因为我们希望保持消费者异步监听消息进程是存活的。
我们将告诉服务器传递消息给我们。由于它将以异步的方式向我们推送消息,我们则需要提供一个回调对象将消息缓冲,直到我们准备使用它们。这就是DeliverCallback所做的:
DeliverCallback deliverCallback = (consumerTag, delivery) -> {
String message = newString(delivery.getBody(), "UTF-8");
System.out.println(" [x] Received '"+ message + "'");
};
channel.basicConsume(QUEUE_NAME, true, deliverCallback, consumerTag -> { });
https://github.com/rabbitmq/rabbitmq-tutorials/blob/master/java/Recv.java
作者:javanoob0660
出处:https://www.cnblogs.com/javanoob0660/articles/16415704.html
版权:本作品采用「署名-非商业性使用-相同方式共享 4.0 国际」许可协议进行许可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通