Rabbitmq教程翻译(三)Publish/Subscribe

发布/订阅

(使用Java客户端)

   在前面的教程中,我们创建了一个工作队列。一个工作队列背后的假设是,每个任务被交付给一个工作者。在这个教程中,我们会做完全不同的东西-我们将邮件传递到多个消费者。这种模式被称为“发布/订阅”。
为了阐明这种模式,我们要建立一个简单的日志记录系统。这将包括两个程序 - 首先会发出日志消息,第二个会接收并打印。

  在我们的记录系统,每个正在运行的副本会得到消息的接收程序。这样,我们将能够运行一个接收器和直接记录到磁盘,并在同一时间,我们就可以运行另一个接收机,并在屏幕上看到的日志。

从本质上讲,发表日志消息广播给所有的接收者。

交换

在以前的教程中,我们在一个队列中发送和接收信息。现在是时候引入完整的消息传递模型在rabbit中。

让我们快速温习下我们在前面的教程中包含的内容:

  •  生产者是一个用户的应用程序发送消息。
  •  队列是消息存储的缓冲区。
  •  消费者是一个用户接收消息的应用程序。

在RabbitMQ的消息模型的核心思想是,生产者从来没有直接发送任何消息到队列。其实,生产者并不知道一个消息将被传递到哪个队列。

相反,生产者只能发送消息的交换(exchange)。交换(exchange)是一个非常简单的事情。它一方面接收到的消息生产者,另一方面将消息推到队列。交换必须知道到底该怎么做它接收的消息。它应该被添加到一个特定的队列?它应该被追加到许多队列?或者它应该被丢弃。所定义的规则是通过交换类型(exchange type)。

有几个交换类型可供选择:directtopicheaders and fanout。我们将重点放在最后一个-the fanout。让我们创建一个这种类型的交换,并调用它记录

channel.exchangeDeclare("logs", "fanout");
扇交换(the fanout exchange)是很简单的。 正如你可能已经猜到了,它只是广播它接收到它所知道的队列的所有消息。 而这正是我们日志系统需要的。

列出所有交换

列出服务器上的交换,你可以运行有用的rabbitmqctl:

$ sudo rabbitmqctl list_exchanges
Listing exchanges ...
        direct
amq.direct      direct
amq.fanout      fanout
amq.headers     headers
amq.match       headers
amq.rabbitmq.log        topic
amq.rabbitmq.trace      topic
amq.topic       topic
logs    fanout
...done.

在这份列表中有一些AMQ *交换和默认(未命名)的交换。默认情况下他们是已经创建的,但它是不可能的,你需要使用它们的那一刻。

无名交换

在以前的教程中,我们不了解交换,但仍然可以将消息发送到队列。这是可能的,因为我们用的是默认的交换,我们确定由空字符串(“” )。

回想一下我们之前发布消息:

channel.basicPublish("", "hello", null, message.getBytes());

第一个参数是该交换(exchange)的名称。空字符串表示默认或无名的交换:消息路由到队列由指定名称的routingKey,如果routingkey存在的话。

现在,我们可以发布到我们命名的交换:

channel.basicPublish( "logs", "", null, message.getBytes());

临时队列

你可能还记得,以前我们使用队列其中有一个指定的名称(记得hello和task_queue?)。能够说出一个队列,对我们来说至关重要-我们需要的工作者指向到同一个队列。给人一种队列名称是很重要的,当你想分享的生产者和消费者之间的队列。

但是这还不是我们的记录器的情况下。我们希望听到所有日志消息,不只是他们的一个子集。我们也只关心在目前流动的消息不会在旧的。要解决这个问题,我们需要两件事情。

首先,当我们连接到rabbit,我们需要一个新的空队列。要做到这一点,我们可以创建一个随机名称的队列,或者甚至更好 - 让服务器为我们选择一个随机队列名称。

其次,一旦断开消费者的队列应该被自动删除。

在Java客户端,当我们没有提供参数到queueDeclare(), 我们创建非持久的,独家的,自动删除队列中生成的名称:

String queueName = channel.queueDeclare().getQueue();

在这一点换queuename包含一个随机的队列名称。例如,它可能看起来像amq.gen JzTY20BRgKO HjmUJj0wLg

绑定

我们已经创造了一个扇出交流和队列。现在,我们需要告诉交换,将消息发送到我们的队列。这种交流和队列之间的关系称为绑定

channel.queueBind(queueName, "logs", "");
从现在 日志 交换消息附加到我们的队列。

Listing bindings

You can list existing bindings using, you guessed it, rabbitmqctl list_bindings.

全部放在一起

生产者程序,它发出的日志消息,看起来并没有太大的不同从以前的教程。最重要的变化是,我们现在要发布的消息,我们的日志,而不是无名的交流。我们需要提供一个routingKey,发送的时候,但它的价值被忽略交流。这里去的代码 脚本EmitLog.java

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
import java.io.IOException;
import com.rabbitmq.client.ConnectionFactory;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.Channel;

public class EmitLog {

    private static final String EXCHANGE_NAME = "logs";

    public static void main(String[] argv)
                  throws java.io.IOException {

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

        channel.exchangeDeclare(EXCHANGE_NAME, "fanout");

        String message = getMessage(argv);

        channel.basicPublish(EXCHANGE_NAME, "", null, message.getBytes());
        System.out.println(" [x] Sent '" + message + "'");

        channel.close();
        connection.close();
    }
    //...
}

(EmitLog.java source)

正如你看到的,在连接建立之后,我们宣布了交流。发布到一个不存在的交换是被禁止的,此步骤是neccesary的。

消息将丢失,如果没有队列势必交流,但是这是我们没关系,消费者如果不听,但我们可以安全地丢弃这个消息。

的代码ReceiveLogs.java

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
import java.io.IOException;
import com.rabbitmq.client.ConnectionFactory;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.QueueingConsumer;

public class ReceiveLogs {

    private static final String EXCHANGE_NAME = "logs";

    public static void main(String[] argv)
                  throws java.io.IOException,
                  java.lang.InterruptedException {

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

        channel.exchangeDeclare(EXCHANGE_NAME, "fanout");
        String queueName = channel.queueDeclare().getQueue();
        channel.queueBind(queueName, EXCHANGE_NAME, "");

        System.out.println(" [*] Waiting for messages. To exit press CTRL+C");

        QueueingConsumer consumer = new QueueingConsumer(channel);
        channel.basicConsume(queueName, true, consumer);

        while (true) {
            QueueingConsumer.Delivery delivery = consumer.nextDelivery();
            String message = new String(delivery.getBody());

            System.out.println(" [x] Received '" + message + "'");
        }
    }
}

(ReceiveLogs.java source)

编译之前,我们就大功告成了。

$ javac -cp rabbitmq-client.jar EmitLog.java ReceiveLogs.java
如果你想将日志保存到一个文件,只需打开一个控制台,然后键入:

$ java -cp .:commons-io-1.2.jar:commons-cli-1.1.jar:rabbitmq-client.jar ReceiveLogs > logs_from_rabbit.log
如果你想在你的屏幕上看到的日志,生成一个新的终端,运行:

$ java -cp .:commons-io-1.2.jar:commons-cli-1.1.jar:rabbitmq-client.jar ReceiveLogs
当然,发出日志类型:

$ java -cp .:commons-io-1.2.jar:commons-cli-1.1.jar:rabbitmq-client.jar EmitLog
使用 用rabbitmqctl list_bindings 您可以验证代码的实际创建绑定和队列,因为我们希望。有两个 ReceiveLogs.java  运行的程序,你应该看到的是这样的:

$ sudo rabbitmqctl list_bindings
Listing bindings ...
logs    exchange        amq.gen-JzTY20BRgKO-HjmUJj0wLg  queue           []
logs    exchange        amq.gen-vso0PVvyiRIL2WoV3i48Yg  queue           []
...done.

结果的解释很简单:数据交换日志两个队列服务器分配的名称。这正是我们打算。

要找出如何监听一个子集的消息,让我们继续前进 教程4






  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Go语言(也称为Golang)是由Google开发的一种静态强类型、编译型的编程语言。它旨在成为一门简单、高效、安全和并发的编程语言,特别适用于构建高性能的服务器和分布式系统。以下是Go语言的一些主要特点和优势: 简洁性:Go语言的语法简单直观,易于学习和使用。它避免了复杂的语法特性,如继承、重载等,转而采用组合和接口来实现代码的复用和扩展。 高性能:Go语言具有出色的性能,可以媲美C和C++。它使用静态类型系统和编译型语言的优势,能够生成高效的机器码。 并发性:Go语言内置了对并发的支持,通过轻量级的goroutine和channel机制,可以轻松实现并发编程。这使得Go语言在构建高性能的服务器和分布式系统时具有天然的优势。 安全性:Go语言具有强大的类型系统和内存管理机制,能够减少运行时错误和内存泄漏等问题。它还支持编译时检查,可以在编译阶段就发现潜在的问题。 标准库:Go语言的标准库非常丰富,包含了大量的实用功能和工具,如网络编程、文件操作、加密解密等。这使得开发者可以更加专注于业务逻辑的实现,而无需花费太多时间在底层功能的实现上。 跨平台:Go语言支持多种操作系统和平台,包括Windows、Linux、macOS等。它使用统一的构建系统(如Go Modules),可以轻松地跨平台编译和运行代码。 开源和社区支持:Go语言是开源的,具有庞大的社区支持和丰富的资源。开发者可以通过社区获取帮助、分享经验和学习资料。 总之,Go语言是一种简单、高效、安全、并发的编程语言,特别适用于构建高性能的服务器和分布式系统。如果你正在寻找一种易于学习和使用的编程语言,并且需要处理大量的并发请求和数据,那么Go语言可能是一个不错的选择。
Go语言(也称为Golang)是由Google开发的一种静态强类型、编译型的编程语言。它旨在成为一门简单、高效、安全和并发的编程语言,特别适用于构建高性能的服务器和分布式系统。以下是Go语言的一些主要特点和优势: 简洁性:Go语言的语法简单直观,易于学习和使用。它避免了复杂的语法特性,如继承、重载等,转而采用组合和接口来实现代码的复用和扩展。 高性能:Go语言具有出色的性能,可以媲美C和C++。它使用静态类型系统和编译型语言的优势,能够生成高效的机器码。 并发性:Go语言内置了对并发的支持,通过轻量级的goroutine和channel机制,可以轻松实现并发编程。这使得Go语言在构建高性能的服务器和分布式系统时具有天然的优势。 安全性:Go语言具有强大的类型系统和内存管理机制,能够减少运行时错误和内存泄漏等问题。它还支持编译时检查,可以在编译阶段就发现潜在的问题。 标准库:Go语言的标准库非常丰富,包含了大量的实用功能和工具,如网络编程、文件操作、加密解密等。这使得开发者可以更加专注于业务逻辑的实现,而无需花费太多时间在底层功能的实现上。 跨平台:Go语言支持多种操作系统和平台,包括Windows、Linux、macOS等。它使用统一的构建系统(如Go Modules),可以轻松地跨平台编译和运行代码。 开源和社区支持:Go语言是开源的,具有庞大的社区支持和丰富的资源。开发者可以通过社区获取帮助、分享经验和学习资料。 总之,Go语言是一种简单、高效、安全、并发的编程语言,特别适用于构建高性能的服务器和分布式系统。如果你正在寻找一种易于学习和使用的编程语言,并且需要处理大量的并发请求和数据,那么Go语言可能是一个不错的选择。
Go语言(也称为Golang)是由Google开发的一种静态强类型、编译型的编程语言。它旨在成为一门简单、高效、安全和并发的编程语言,特别适用于构建高性能的服务器和分布式系统。以下是Go语言的一些主要特点和优势: 简洁性:Go语言的语法简单直观,易于学习和使用。它避免了复杂的语法特性,如继承、重载等,转而采用组合和接口来实现代码的复用和扩展。 高性能:Go语言具有出色的性能,可以媲美C和C++。它使用静态类型系统和编译型语言的优势,能够生成高效的机器码。 并发性:Go语言内置了对并发的支持,通过轻量级的goroutine和channel机制,可以轻松实现并发编程。这使得Go语言在构建高性能的服务器和分布式系统时具有天然的优势。 安全性:Go语言具有强大的类型系统和内存管理机制,能够减少运行时错误和内存泄漏等问题。它还支持编译时检查,可以在编译阶段就发现潜在的问题。 标准库:Go语言的标准库非常丰富,包含了大量的实用功能和工具,如网络编程、文件操作、加密解密等。这使得开发者可以更加专注于业务逻辑的实现,而无需花费太多时间在底层功能的实现上。 跨平台:Go语言支持多种操作系统和平台,包括Windows、Linux、macOS等。它使用统一的构建系统(如Go Modules),可以轻松地跨平台编译和运行代码。 开源和社区支持:Go语言是开源的,具有庞大的社区支持和丰富的资源。开发者可以通过社区获取帮助、分享经验和学习资料。 总之,Go语言是一种简单、高效、安全、并发的编程语言,特别适用于构建高性能的服务器和分布式系统。如果你正在寻找一种易于学习和使用的编程语言,并且需要处理大量的并发请求和数据,那么Go语言可能是一个不错的选择。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值