RabbitMQ Guide 4: Routing and Direct Exchange

 In the previous chapter, we built a simple logging system where we can broadcast messages to many consumers. In this chapter we will add a feature: we can subscribe to some of these messages. For example, we want to only store errors at the error level to the hard disk, and at the same time, we can print logs of all levels (error, info, warning, etc.) to the console.

1. Bindings

  In the previous chapter, we have created the binding relationship, review the code:

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

  A binding is a relationship between an exchange and a queue. Meaning: This queue is interested in messages from this exchange.

  This method also has another routing Key parameter. In order to avoid confusion with the routing key generated by the basic_public parameter, we call it a binding key. The following shows how to create a binding key through a binding key. Bind:

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

  Note that the meaning of this binding key (here "black") depends on the type of exchange. For example, in our logging system, the exchange type is fanout, at this time, the binding key has no meaning and will be ignored.

2. Direct Exchange

  In our previous log system, all messages were broadcast to all consumers, but the need for this chapter is to have a program that can only receive error-level logs and save them to disk without wasting space to store those info, warning level log.

  The broadcast mode switch we're using isn't flexible enough, it just broadcasts without thinking. Therefore, direct exchange needs to be used instead. The routing algorithm for a directly connected exchange is very simple: push a message to a queue with the same binding key as the routing key for the message.

  To illustrate this, look at the image below:

  In this figure, two queues are bound on the directly connected switch X. The first queue is bound with the binding key orange, and the second queue has two binding keys: black and green. In this scenario, a message with a routing key of orange at the time of delivery will only be routed to queue Q1, and messages with routing keys of black and green will be routed to queue Q2. All other messages will be lost.

3. Multiple binding

  The same binding key can be bound to different queues. In the above figure, we can also add a binding key between the exchange X and the queue Q2. In this case, the directly connected exchange will exchange with the broadcast. The server has the same behavior, pushing the message to all matching queues. A message with routing key black will be pushed to both queues Q1 and Q2.

4. Send log

First we'll create an exchange as always:

1 channel.exchangeDeclare(EXCHANGE_NAME, "direct");

  and ready to send a message:

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

  We need to make sure that the parameter "severity" in our logging system is one of "info", "warning" and "error".

5. Subscribe

Creating a receiving message is basically the same as the previous chapter, the only difference is that you need to specify the value of severity when creating a binding relationship:

1 String queueName = channel.queueDeclare().getQueue();
2 
3 for(String severity : argv){
4   channel.queueBind(queueName, EXCHANGE_NAME, severity);
5 }

6. Complete code

  EmitLogDirect.java

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

public class EmitLogDirect {

  private static final String EXCHANGE_NAME = "direct_logs";

  public static void main(String[] argv) throws Exception {
    ConnectionFactory factory = new ConnectionFactory();
    factory.setHost("localhost");
    try (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("UTF-8"));
        System.out.println(" [x] Sent '" + severity + "':'" + message + "'");
    }
  }
  //..
}

  ReceiveLogsDirect.java

import com.rabbitmq.client.*;

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");

    DeliverCallback deliverCallback = (consumerTag, delivery) -> {
        String message = new String(delivery.getBody(), "UTF-8");
        System.out.println(" [x] Received '" +
            delivery.getEnvelope().getRoutingKey() + "':'" + message + "'");
    };
    channel.basicConsume(queueName, true, deliverCallback, consumerTag -> { });
  }
}

  For the convenience of testing, we can bind "info", "error", and "warning" to a queue, and then the producer sends messages to "info", "error", and "warning" respectively:

  View the RabbitMq console at this point:

Pay attention, don't get lost, this is a public account that programmers want to pay attention to

{{o.name}}
{{m.name}}

Guess you like

Origin http://10.200.1.11:23101/article/api/json?id=324122299&siteId=291194637