RabbitMQ教程 (四): Routing 路由

Routing

(using the Java client)

Prerequisites

  This tutorial assumes RabbitMQ is installed and running on localhost on standard port (5672). In case you use a different host, port or credentials, connections settings would require adjusting.

Where to get help

  If you’re having trouble going through this tutorial you can contact us through the mailing list.

  In the previous tutorial we built a simple logging system. We were able to broadcast log messages to many receivers.
  在上一个教程中,我们构建了一个简单的日志系统 我们能够向许多接收者广播日志消息。

  In this tutorial we’re going to add a feature to it - we’re going to make it possible to subscribe only to a subset of the messages. For example, we will be able to direct only critical error messages to the log file (to save disk space), while still being able to print all of the log messages on the console.
  在本教程中,我们将为其添加一个功能 - 我们将只能订阅一部分消息。例如,我们只能将关键错误消息定向到日志文件(以节省磁盘空间),同时仍然能够在控制台上打印所有日志消息。

Bindings 绑定

  In previous examples we were already creating bindings. You may recall code like:
  在前面的例子中,我们已经在创建绑定。您可能会记得以下代码:

  channel.queueBind(queueName, EXCHANGE_NAME, "");

  A binding is a relationship between an exchange and a queue. This can be simply read as: the queue is interested in messages from this exchange.
  绑定是交换器和队列之间的关系。这可以简单地理解为:队列对来自此交换器的消息感兴趣。

  Bindings can take an extra routingKey parameter. To avoid the confusion with a basic_publish parameter we’re going to call it a binding key. This is how we could create a binding with a key:
  绑定可以采用额外的routingKey参数。为了避免与basic_publish参数混淆,我们将其称为 绑定键。这就是我们如何使用键创建绑定:

  channel.queueBind(queueName, EXCHANGE_NAME, "black");

  The meaning of a binding key depends on the exchange type. The fanout exchanges, which we used previously, simply ignored its value.
  绑定密钥的含义取决于交换类型。我们之前使用的 fanout扇出交换器只是忽略了它的 值。

Direct exchange 直接交换器

  Our logging system from the previous tutorial broadcasts all messages to all consumers. We want to extend that to allow filtering messages based on their severity. For example we may want a program which writes log messages to the disk to only receive critical errors, and not waste disk space on warning or info log messages.
   我们上一个教程中的日志记录系统向所有消费者广播所有消息。我们希望扩展它以允许根据消息的严重性过滤消息。例如,我们可能需要一个程序将日志消息写入磁盘以仅接收严重错误,而不是在警告或信息日志消息上浪费磁盘空间。

  We were using a fanout exchange, which doesn’t give us much flexibility - it’s only capable of mindless broadcasting.
  我们使用的是 fanout扇出交换器,它没有给我们太大的灵活性 - 它只能进行无意识的广播。

  We will use a direct exchange instead. The routing algorithm behind a direct exchange is simple - a message goes to the queues whose binding key exactly matches the routing key of the message.
  我们将使用direct直接交换器。direct直接交换器背后的路由算法很简单 - 消息进入队列,其 绑定路由键 与消息的路由键 完全匹配。

  To illustrate that, consider the following setup:
  为了说明这一点,请考虑以下设置:
在这里插入图片描述

  In this setup, we can see the direct exchange X with two queues bound to it. The first queue is bound with binding key orange, and the second has two bindings, one with binding key black and the other one with green.
  在此设置中,我们可以看到直接交换器 X与两个绑定到它的队列。第一个队列绑定橙色绑定,第二个绑定有两个绑定,一个绑定路由键 为黑色,另一个绑定路由键 为绿色。

  In such a setup a message published to the exchange with a routing key orange will be routed to queue Q1. Messages with a routing key of black or green will go to Q2. All other messages will be discarded.
  在这样的设置中,使用路由密钥orange发布到交换机的消息 将被路由到队列Q1。路由键为黑色 或绿色的消息将转到Q2。所有其他消息将被丢弃。

Multiple bindings 多个绑定

在这里插入图片描述
  It is perfectly legal to bind multiple queues with the same binding key. In our example we could add a binding between X and Q1 with binding key black. In that case, the direct exchange will behave like fanout and will broadcast the message to all the matching queues. A message with routing key black will be delivered to both Q1 and Q2.
  使用相同的绑定密钥绑定多个队列是完全合法的。在我们的例子中,我们可以在X和Q1之间添加绑定键黑色的绑定。在这种情况下,直接交换将表现得像扇出一样,并将消息广播到所有匹配的队列。路由密钥为黑色的消息将传送到 Q1和Q2。

Emitting logs 发送日志

  We’ll use this model for our logging system. Instead of fanout we’ll send messages to a direct exchange. We will supply the log severity as a routing key. That way the receiving program will be able to select the severity it wants to receive. Let’s focus on emitting logs first.
  我们将此模型用于我们的日志系统。我们会将消息发送给direct直接交换器,而不是fanout扇出交换器。我们将提供日志严重性作为路由键。这样接收程序将能够选择它想要接收的严重性。让我们首先关注发送日志。

  As always, we need to create an exchange first:
  一如既往,我们需要先创建一个交换器:

  channel.exchangeDeclare(EXCHANGE_NAME, "direct");

  And we’re ready to send a message:我们已准备好发送消息:

  channel.basicPublish(EXCHANGE_NAME, severity, null, message.getBytes());

To simplify things we will assume that ‘severity’ can be one of ‘info’, ‘warning’, ‘error’.
为简化起见,我们假设“严重性”可以是“信息”,“警告”,“错误”之一。

Subscribing 订阅

Receiving messages will work just like in the previous tutorial, with one exception - we’re going to create a new binding for each severity we’re interested in.
接收消息将像上一个教程一样工作,但有一个例外 - 我们将为我们感兴趣的每个严重性创建一个新的绑定。

	String queueName = channel.queueDeclare().getQueue();
	
	for(String severity : argv){
	  channel.queueBind(queueName, EXCHANGE_NAME, severity);
	}

Putting it all together 整合在一起

在这里插入图片描述

The code for EmitLogDirect.java class:

	import com.rabbitmq.client.*;
	
	import java.io.IOException;
	
	public class EmitLogDirect {
	
	    private static final String EXCHANGE_NAME = "direct_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, "direct");
	
	        String severity = getSeverity(argv);
	        String message = getMessage(argv);
	
	        channel.basicPublish(EXCHANGE_NAME, severity, null, message.getBytes());
	        System.out.println(" [x] Sent '" + severity + "':'" + message + "'");
	
	        channel.close();
	        connection.close();
	    }
	    //..
	}

The code for ReceiveLogsDirect.java:

	import com.rabbitmq.client.*;
	
	import java.io.IOException;
	
	public class ReceiveLogsDirect {
	
	  private static final String EXCHANGE_NAME = "direct_logs";
	
	  public static void main(String[] argv) throws Exception {
	    ConnectionFactory factory = new ConnectionFactory();
	    factory.setHost("localhost");
	    Connection connection = factory.newConnection();
	    Channel channel = connection.createChannel();
	
	    channel.exchangeDeclare(EXCHANGE_NAME, "direct");
	    String queueName = channel.queueDeclare().getQueue();
	
	    if (argv.length < 1){
	      System.err.println("Usage: ReceiveLogsDirect [info] [warning] [error]");
	      System.exit(1);
	    }
	
	    for(String severity : argv){
	      channel.queueBind(queueName, EXCHANGE_NAME, severity);
	    }
	    System.out.println(" [*] Waiting for messages. To exit press CTRL+C");
	
	    Consumer consumer = new DefaultConsumer(channel) {
	      @Override
	      public void handleDelivery(String consumerTag, Envelope envelope,
	                                 AMQP.BasicProperties properties, byte[] body) throws IOException {
	        String message = new String(body, "UTF-8");
	        System.out.println(" [x] Received '" + envelope.getRoutingKey() + "':'" + message + "'");
	      }
	    };
	    channel.basicConsume(queueName, true, consumer);
	  }
	}

Compile as usual (see tutorial one for compilation and classpath advice). For convenience we’ll use an environment variable C P ( t h a t ′ s 像 往 常 一 样 编 译 ( 有 关 编 译 和 类 路 径 建 议 , 请 参 阅 教 程 一 ) 。 为 方 便 起 见 , 我 们 将 在 运 行 示 例 时 使 用 环 境 变 量 CP (that&#x27;s %CP% on Windows) for the classpath when running examples. 像往常一样编译(有关编译和类路径建议,请参阅教程一)。为方便起见,我们将在运行示例时使用环境变量 CP(thats便使 CP(在Windows上为%CP%)作为类路径。

  javac -cp $CP ReceiveLogsDirect.java EmitLogDirect.java

If you want to save only ‘warning’ and ‘error’ (and not ‘info’) log messages to a file, just open a console and type:
如果您只想将“警告”和“错误”(而不是“信息”)日志消息保存到文件,只需打开控制台并键入:

  java -cp $CP ReceiveLogsDirect warning error > logs_from_rabbit.log

If you’d like to see all the log messages on your screen, open a new terminal and do:
如果您想在屏幕上看到所有日志消息,请打开一个新终端并执行以下操作:

  java -cp $CP ReceiveLogsDirect info warning error
  # => [*] Waiting for logs. To exit press CTRL+C

And, for example, to emit an error log message just type:
并且,例如,要发出错误日志消息,只需键入:

  java -cp $CP EmitLogDirect error "Run. Run. Or it will explode."
  # => [x] Sent 'error':'Run. Run. Or it will explode.'

(Full source code for (EmitLogDirect.java source) and (ReceiveLogsDirect.java source))

Move on to tutorial 5 to find out how to listen for messages based on a pattern.
转到教程5,了解如何根据模式监听消息。

Production [Non-]Suitability Disclaimer

Please keep in mind that this and other tutorials are, well, tutorials. They demonstrate one new concept at a time and may intentionally oversimplify some things and leave out others. For example topics such as connection management, error handling, connection recovery, concurrency and metric collection are largely omitted for the sake of brevity. Such simplified code should not be considered production ready.

Please take a look at the rest of the documentation before going live with your app. We particularly recommend the following guides: Publisher Confirms and Consumer Acknowledgements, Production Checklist and Monitoring.

Getting Help and Providing Feedback

If you have questions about the contents of this tutorial or any other topic related to RabbitMQ, don’t hesitate to ask them on the RabbitMQ mailing list.

Help Us Improve the Docs ❤️

If you’d like to contribute an improvement to the site, its source is available on GitHub. Simply fork the repository and submit a pull request. Thank you!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值