RabbitMQ 手册 - "Hello World"

英文原文链接

介绍

准备

本手册假定RabbitMQ已经安装并且运行在本机,监听了标准的5672端口。如果你使用了不同的主机,端口或者凭证,连接设置也需要相应地调整。

从哪里获取帮助

如果你在阅读本手册有任何困惑,可以通过邮件列表联系我们

RabbitMQ是一个消息代理:它接受并转发消息。你可以认为他是一个邮局:当你在邮箱放了一封你想邮送的信件,你可以确定某个邮递员最终会将邮件送达给收件人。在这个类比中,RabbitMQ是一个邮箱,邮局和一个邮递员。

RabbitMQ和邮局主要的不同在于它不真正处理纸件,与之替代的是它接受,存储并转发数据的二进制块 - 消息。

RabbitMQ和平常的消息传送,使用一些行业术语。

  • 生产者 仅仅意味着发送。发送消息的程序是一个生产者
    producer.png
  • 队列 是一个在RabbitMQ中的邮箱名。尽管消息流经RabbitMQ和你的程序程序,它们可以只存储在队列 里。队列 只受主机的内存和磁盘限制,它基本上是一个大的消息缓冲器。多个生产者 可以发送消息到同一个队列,并且多个消费者也可以从同一个队列接收数据。下面代表了一个队列:
    queue.png
  • 消费 和接收的意思相近。消费者 是一个等待接收消息的程序:
    consumer.png

注意,生产者,消费者和代理不必要在同一台主机上;大部分应用中它们确实不在同一台主机上。一个应用也可以同时是生产者和消费者。

"Hello World"

(使用Java客户端)

在手册的本部分,我们将使用Java写两个程序;一个发送单个消息的生产者,和一个接受并打印这些消息的消费者。我们将隐藏这些JAVA API的一些细节,并将注意力放在上手这件非常简单的事情上。它就是“Hello World”消息。

在下面这个图片中,“P” 是我们的生产者,“C”是我们的消费者。中间的盒子是一个队列 - 一个RabbitMQ为消费者保存的消息缓冲器。

python-one.png

Java客户端库

RabbitMQ支持多种协议。本手册使用AMQP 0-9-1, 是一个开源的,通用的消息协议。

这里有很多不同语言的RabbitMQ客户端。我们将使用有RabbitMQ提供的Java客户端。下载 客户端库和它的依赖(SLF4J API和SLF4J Simple)。

拷贝这些文件到你的工作目录,和手册中的Java文件放在一起。

请注意SLF4J Simple对于手册来说已经足够了,但是你应该使用一个像Logback一样的成熟的日志库。

(RabbitMQ Java客户端也在中央Maven仓库,groupId是com.rabbitmq,artifactId 是amqp-client)

现在我们已经有了Java客户端和它的所有依赖,我们可以写代码了。

发送

sending.png

我们将调用我们的消息发布器(发送者)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 {
      ...
  }
}    

然后我们可以创建一个到服务器的连接:

ConnectionFactory factory = new ConnectionFactory();
factory.setHost("localhost");
try (Connection connection = factory.newConnection();
     Channel channel = connection.createChannel()) {

}

这个连接将socket连接抽象化,帮我们完成协议版本的协商和认证等。这里我们连接到本机的一个代理 - 因此是 localhost 。如果我们想连接到一个不同机器上的代理,我们只要在这里简单地指定它的名称或者IP地址。

接下来我们创建一个channal,是大多数做事情的API所在之处。注意,我们可以使用一个try-with-resources声明,因为ConnectionChannel 实现了 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 + "'");

声明队列具有幂等性 - 仅在不存在时创建。消息内容是字节数组,所以可以在这里编码任何你喜欢的东西。

完整的Send.java类.

发送不成功!

如果这是你第一次使用RabbitMQ,而且你没有看到发送的消息,你可能会苦思冥想哪里出错了。也许是代理没有足够的磁盘空间去启动(默认需要至少200M空闲空间),所以拒绝接受消息。检查代理日志文件,确保必要时减少磁盘空间限制,配置文件文档 会告诉你如何设置disk_free_limit.

接收

上面是我们的发布者。我们的消费者监听来自RabbitMQ的消息,所以不像发布单个消息的发布者,我们将让它保持运行,以便监听消息并将它们打印出来。


receiving.png

这段代码 (Recv.java) 几乎和 Send 的导入是一样的:

import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;
import com.rabbitmq.client.DeliverCallback;

DefaultConsumer是一个实现了Consumer接口的类,我们将使用它缓存由服务端推送给我们的消息。

和发布者的创建过程一样;我们打开一个连接和一个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 = new String(delivery.getBody(), "UTF-8");
    System.out.println(" [x] Received '" + message + "'");
};
channel.basicConsume(QUEUE_NAME, true, deliverCallback, consumerTag -> { });

完整的Recv.java类.

将它们放一起

你可以使用classpath下的RabbitMQ客户端同时编译它们:

javac -cp amqp-client-5.7.1.jar Send.java Recv.java

要运行它们,你将需要在classpath中有rabbitmq-client.jar和它的依赖。在终端运行消费者(接收者):

java -cp .:amqp-client-5.7.1.jar:slf4j-api-1.7.26.jar:slf4j-simple-1.7.26.jar Recv

然后,运行发布者(发送者):

java -cp .:amqp-client-5.7.1.jar:slf4j-api-1.7.26.jar:slf4j-simple-1.7.26.jar Send

在Windows中,在classpath中使用分号代替冒号去分割条目。

消费者将打印它通过RabbitMQ从发布者那里获取的消息。消费者将保持运行,等待消息(使用Ctrl-C停止),所以尝试在另外的终端运行发布者。

列出队列

你可能希望看到RabbitMQ有哪些队列和队列中有多少消息。你可以使用rabbitmqctl工具做到(使用特权用户):

sudo rabbitmqctl list_queues

在 Windows 中, 省略sudo:

rabbitmqctl.bat list_queues

是时候去第二部分创建一个简单的 工作队列 了。

小提示

想保存敲的命令,你可以为classpath设置一个环境变量, 例如:

export CP=.:amqp-client-5.7.1.jar:slf4j-api-1.7.26.jar:slf4j-simple-1.7.26.jar
java -cp $CP Send

或者在 Windows:

set CP=.;amqp-client-5.7.1.jar;slf4j-api-1.7.26.jar;slf4j-simple-1.7.26.jar
java -cp %CP% Send

你可能感兴趣的:(RabbitMQ 手册 - "Hello World")