RabbitMQ topic (Topic) (6)

Although using the direct type improves our system, there are still some limitations: it cannot perform routing based on multiple conditions.
In our logging system, it is possible that we want to subscribe based not only on the level of the log but also on the source of the log. This concept is similar to unix tools: syslog, which forwards logs based on severity (info/warning/crit...) and device (auth/cron/kern...)
This may give us more flexibility: we may only want to subscribe from 'cron ' fatal error log, not from 'kern'.
To implement the above requirements in our system, we need to learn a slightly more complex topic type of topic exchange.

1. Topic Exchange
Messages sent to forwarders of topic type cannot have a routing key (routing_key) set arbitrarily, but must consist of a series of identifiers separated by dots. An identifier can be anything, but is generally related to some characteristic of the message. Some examples of valid selection keys: "stock.usd.nyse", "nyse.vmw", "quick.orange.rabbit". You can define any number of identifiers, up to a limit of 255 bytes.
Bind keys have the same form as select keys. The logic behind topic-type forwarders is similar to direct-type forwarders: a specific selector key will be forwarded to the queue whose binding key matches. Note: There are two special cases of binding keys.
* can match an identifier.
# can match 0 or more identifiers.
2. Diagram:
We are ready to send a message about animals. The message is appended with a select key containing 3 identifiers (separated by two dots). The first identifier describes the speed of the animal, the second the color of the animal, and the third the species of the animal: <speed>.<color>.<species>.
We create 3 binding keys: Q1 is bound to *.orange.* Q2 is bound to *.*.rabbit and lazy.#.
Simply think:
Q1 is interested in all orange animals.
Q2 wants to know all about rabbits and all about lazy animals.
A message with a selection key of quick.orange.rabbit will be forwarded to both queues. Messages with lazy.orange.elephant are also forwarded to both queues. On the other hand quick.orange.fox will only be forwarded to Q1, and lazy.brown.fox will be forwarded to Q2. lazy.pink.rabbit matches both binding keys, but will only be forwarded to Q2 once. quick.brown.fox cannot match any binding key, so it will be discarded.
If we break our convention and send a selection key of one or four identifiers, like: orange, quick.orange.male.rabbit, these selection keys cannot match any binding keys, so the message will be discarded.
On the other hand, lazy.orange.male.rabbit, despite being four identifiers, can also be matched with lazy.# and forwarded to Q2.
Note: Topic type repeaters are very powerful and can implement other types of repeaters.
When a queue is bound with the binding key #, all messages will be received, similar to a fanout type repeater.

When the binding key does not contain any # and *, it is similar to the direct type forwarder.

The reference code is as follows:

package wenjie.topic;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;
/**
 * Created by Gongwenjie on 2018-05-08
 */
public class TopicSend {

    private static final String EXCHANGE_NAME = "topic_logs";

    public static void main(String[] argv) {
        Connection connection = null;
        Channel channel = null;
        try {
            ConnectionFactory factory = new ConnectionFactory();
            factory.setHost("localhost");

            connection = factory.newConnection();
            channel = connection.createChannel();
// declare an exchange that matches the pattern
            channel.exchangeDeclare(EXCHANGE_NAME, "topic");

            // message to send
            String[] routingKeys = new String[]{"quick.orange.rabbit",
                    "lazy.orange.elephant",
                    "quick.orange.fox",
                    "lazy.brown.fox",
                    "quick.brown.fox",
                    "quick.orange.male.rabbit",
                    "lazy.orange.male.rabbit"};
// send messages
            for(String severity :routingKeys){
                String message = "From "+severity+" routingKey' s message!";
                channel.basicPublish(EXCHANGE_NAME, severity, null, message.getBytes());
                System.out.println("TopicSend [x] Sent '" + severity + "':'" + message + "'");
            }

        } catch (Exception e) {
            e.printStackTrace ();
        } finally {
            if (connection != null) {
                try {
                    connection.close();
                } catch (Exception ignore) {
                }
            }
        }
    }
}
package wenjie.topic;

import com.rabbitmq.client.*;

import java.io.IOException;

/**
 * Created by Gongwenjie on 2018-05-08
 */
public class ReceiveLogsTopic1 {

    private static final String EXCHANGE_NAME = "topic_logs";

    public static void main(String[] argv) throws Exception {
        ConnectionFactory factory = new ConnectionFactory();
        factory.setHost("localhost");
        Connection connection = factory.newConnection();
        Channel channel = connection.createChannel();
// declare an exchange that matches the pattern
        channel.exchangeDeclare(EXCHANGE_NAME, "topic");
        String queueName = channel.queueDeclare().getQueue();
        // route key
        String[] routingKeys = new String[]{"*.orange.*"};
// bind routing key
        for (String bindingKey : routingKeys) {
            channel.queueBind(queueName, EXCHANGE_NAME, bindingKey);
            System.out.println("ReceiveLogsTopic1 exchange:"+EXCHANGE_NAME+", queue:"+queueName+", BindRoutingKey:" + bindingKey);
        }

        System.out.println("ReceiveLogsTopic1 [*] 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("ReceiveLogsTopic1 [x] Received '" + envelope.getRoutingKey() + "':'" + message + "'");
            }
        };
        channel.basicConsume(queueName, true, consumer);
    }
}
package wenjie.topic;

import com.rabbitmq.client.*;

import java.io.IOException;

/**
 * Created by Gongwenjie on 2018-05-08
 */
public class ReceiveLogsTopic2 {

    private static final String EXCHANGE_NAME = "topic_logs";

    public static void main(String[] argv) throws Exception {
        ConnectionFactory factory = new ConnectionFactory();
        factory.setHost("localhost");
        Connection connection = factory.newConnection();
        Channel channel = connection.createChannel();
// declare an exchange that matches the pattern
        channel.exchangeDeclare(EXCHANGE_NAME, "topic");
        String queueName = channel.queueDeclare().getQueue();
        // route key
        String[] routingKeys = new String[]{"*.*.rabbit", "lazy.#"};
// bind routing key
        for (String bindingKey : routingKeys) {
            channel.queueBind(queueName, EXCHANGE_NAME, bindingKey);
            System.out.println("ReceiveLogsTopic2 exchange:"+EXCHANGE_NAME+", queue:"+queueName+", BindRoutingKey:" + bindingKey);
        }

        System.out.println("ReceiveLogsTopic2 [*] 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("ReceiveLogsTopic2 [x] Received '" + envelope.getRoutingKey() + "':'" + message + "'");
            }
        };
        channel.basicConsume(queueName, true, consumer);
    }
}

The output is as follows:

TopicSend [x] Sent 'quick.orange.rabbit':'From quick.orange.rabbit routingKey' s message!'
TopicSend [x] Sent 'lazy.orange.elephant':'From lazy.orange.elephant routingKey' s message!'
TopicSend [x] Sent 'quick.orange.fox':'From quick.orange.fox routingKey' s message!'
TopicSend [x] Sent 'lazy.brown.fox':'From lazy.brown.fox routingKey' s message!'
TopicSend [x] Sent 'quick.brown.fox':'From quick.brown.fox routingKey' s message!'
TopicSend [x] Sent 'quick.orange.male.rabbit':'From quick.orange.male.rabbit routingKey' s message!'
TopicSend [x] Sent 'lazy.orange.male.rabbit':'From lazy.orange.male.rabbit routingKey' s message!'

Process finished with exit code 0
ReceiveLogsTopic1 exchange:topic_logs, queue:amq.gen-7MSL7bu4hgzoMkQdY2LpyA, BindRoutingKey:*.orange.*
ReceiveLogsTopic1 [*] Waiting for messages. To exit press CTRL+C
ReceiveLogsTopic1 [x] Received 'quick.orange.rabbit':'From quick.orange.rabbit routingKey' s message!'
ReceiveLogsTopic1 [x] Received 'lazy.orange.elephant':'From lazy.orange.elephant routingKey' s message!'
ReceiveLogsTopic1 [x] Received 'quick.orange.fox':'From quick.orange.fox routingKey' s message!'
ReceiveLogsTopic2 exchange:topic_logs, queue:amq.gen-EF5jrwNv4QyPV2Ad9GNA7A, BindRoutingKey:*.*.rabbit
ReceiveLogsTopic2 exchange:topic_logs, queue:amq.gen-EF5jrwNv4QyPV2Ad9GNA7A, BindRoutingKey:lazy.#
ReceiveLogsTopic2 [*] Waiting for messages. To exit press CTRL+C
ReceiveLogsTopic2 [x] Received 'quick.orange.rabbit':'From quick.orange.rabbit routingKey' s message!'
ReceiveLogsTopic2 [x] Received 'lazy.orange.elephant':'From lazy.orange.elephant routingKey' s message!'
ReceiveLogsTopic2 [x] Received 'lazy.brown.fox':'From lazy.brown.fox routingKey' s message!'
ReceiveLogsTopic2 [x] Received 'lazy.orange.male.rabbit':'From lazy.orange.male.rabbit routingKey' s message!'





Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=326139824&siteId=291194637