[RabbitMQ][官方文档翻译]Hello World

官方文档

介绍
RabbitMQ是一个消息中介。它能接收和推送消息。可以将它想象成一个邮局。当你往邮箱中放入你的邮件时,你可以确定邮递员最终会将邮件递送给收件人。RabbitMQ就是邮箱、邮局和邮递员。

RabbitMQ和邮局的主要区别在于它处理的不是纸张。它接收、存储、推送的是二进制数据消息。

RabbitMQ和一般的消息传递使用一些专业术语:

  • 生产无非就是发送,发送消息的程序就是生产者:
    image
  • 队列就是RabbitMQ里的邮箱。尽管消息会在RabbitMQ和您的应用程序之间流通,但是它们只能被存储在队列中。一个队列只会受到主机的内存和磁盘的限制。它显然是一个巨大的消息缓冲器。多个生产者可以给同一个队列发送消息,多个消费者也可以从同一个队列中获取消息。我们用以下图案表示队列:
    image
  • 消费就是获取消息。消费者是一个主要等待接收信息的程序:
    image

请注意!生产者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客户端和对应依赖,我们可以编写一些代码了。

发送
image
我们称消息发布者(发送者)为 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中监听消息。所以不像发送者发送一条消息,我们会为了监听消息和打印消息保持消费者运行。
image
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 国际」许可协议进行许可。

posted @   丘丘CRUD  阅读(126)  评论(0编辑  收藏  举报
编辑推荐:
· 基于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最大的设计失误
· 单元测试从入门到精通
more_horiz
keyboard_arrow_up dark_mode palette
选择主题
点击右上角即可分享
微信分享提示