[Learning RabbitMQ from Official Documents] 4. Routing Patterns of RABBITMQ-ROUTING

Posted by ac1982 on Sun, 09 Jun 2019 21:19:27 +0200

In the previous tutorial, we built a simple logging system. We have been able to send log messages to many consumers.
In this installment, we'll make some changes to add a feature to it that allows it to subscribe to only a part of the message. For example, we can only point fatal error messages to log files (saving disk space), and we can print all log messages on the console.
binding
In the previous examples, we have used bindings. Recall this code:

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

Binding is a connection between the switch and the queue. We can simply interpret it as: queues are interested in the information in this switch ~ (manual funny ~)

Binding can accept an additional Routing Key parameter. To avoid confusion with the basic_publish parameter, we can call it a binding key. That's how we create a binding with key.

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

The meaning of a binding key depends on the type of exchange. We used the fanout type before, but we ignored its value.

Direct Exchange

In the previous issue, our logging system was able to send messages to all consumers. We want to extend this functionality, and we want to filter these messages based on the severity of these logs. Let's take a chestnut: We might want a program that can write log messages to disk. This program only accepts one kind of log, the log of Customs key errors. Because we don't need to waste disk space on warnings and different information.

We used fanout switching before, but at this point, it seems less flexible - it can only broadcast unconsciously, that is to say, to everyone. This time we will use the direct switch type, and the routing algorithm behind the dierct switch type is simple: the message will be passed to the queue that matches its own outingkey exactly.
To understand this, please see the picture:


direct-exchange


In this diagram, we can see an X, which is a direct type switch. The first queue is bound to an orange orange, and the second queue has two bindings, black black and green. Under such a switching mechanism, a message whose routing key is orange is published to the switch, which will be bound to Q1. Send a message whose routing key is black or green to the switch, which will be bound to Q2. All other news will be discarded.

Multiple bindings


Multiple bindings


It would be perfectly legal to bind multiple queues with the same binding key. In our example, we can add a black binding key between X and Q1. In this case, direct exchange will behave as fanout exchange and broadcast messages to all matching queues. A message with a black routing key will be sent to Q1 and Q2

Send logs - Emitting logs

We will use this model for our logging system. We will replace the previous fanout type with the direct type. We will use the severity of the log as the routing key. In this way, the acceptor will be able to select the message it wants to receive through control. Let's focus on sending logs.
As usual, we first need to create a switch:

channel.exchangeDeclare(EXCHANGE_NAME,"direct");

We are going to send a message:

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

To simplify the problem, we assume that severity is divided into three levels: info, warn and error.

Subscribing

The procedure for receiving messages is basically the same as before, except that we will create a binding of information for the "severity" we are interested in.

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

Complete procedure


Routing mode


EmitLogDirect.java

public class EmitLogDirect {

    //Set the name of the switch
    private static final String EXCHANGE_NAME = "direct_logs";

    public static void main(String[] args) throws IOException {
        //Get the connection
        Connection connection = ConnectionUtil.getConnection();
        //Create channels
        Channel channel = connection.createChannel();
        //Declare the switch, give it a name, and set the exchange type to direct
        channel.exchangeDeclare(EXCHANGE_NAME,"direct");
        //Setting severity manually in code
        String severity = getSeverity(args);
        //Message content to be delivered
        String message = getMessage(args);
        //send message
        channel.basicPublish(EXCHANGE_NAME,severity,null,message.getBytes());
        System.out.println("[x] Sent '"+severity+"':'"+message+"'");
        //Close the connection channel
        channel.close();
        connection.close();
    }

    private static String getSeverity(String[] strings) {
        if (strings.length<1){
            return "info";
        }
        return strings[0];
    }

    private static String getMessage(String[] strings) {
        if (strings.length<2){
            return "hello world";
        }
        return joinStrings(strings," ",1);
    }

    private static String joinStrings(String[] strings, String delimiter,int startIndex) {
        int length = strings.length;
        if (length == 0){
            return "";
        }
        if (length<startIndex){
            return "";
        }
        StringBuilder words = new StringBuilder(strings[startIndex]);
        for (int i = startIndex+1 ; i < length; i++){
            words.append(delimiter).append(strings[i]);
        }
        return words.toString();
    }
}

ReceiveLogDirect.java

public class ReceiveLogsDirect {

    //Set the name of the switch
    private static final String EXCHANGE_NAME = "direct_logs";

    public static void main(String[] args) throws IOException {
        //Get the connection
        Connection connection = ConnectionUtil.getConnection();
        //Create channels
        Channel channel = connection.createChannel();
        //Declare the switch, give it a name, and set the exchange type to direct
        channel.exchangeDeclare(EXCHANGE_NAME,"direct");
        //Get the name of the queue
        String queueName = channel.queueDeclare().getQueue();
        //Truncate the input error
        if (args.length<1){
            System.err.println("Usage: ReceiveLogsDirect [info] [warning] [error]");
            System.exit(1);
        }
        //At the same time, let's see how much logging we really need.
        String wholeSeverity = "";
        //According to the input, determine the "severity" that the program wants to collect and bind.
        for (String severity : args){
            channel.queueBind(queueName,EXCHANGE_NAME,severity);
            wholeSeverity = wholeSeverity+" "+severity;
        }

        System.out.println("[*] Waiting for"+wholeSeverity+" message.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);
    }
}

Once again prove that they are not simply sticky code!!!
I found the original version a little inhumane when I tested it here, so I added a wholeServerity to receive, and when I started the program, I told us how serious it could be charged.
Stick the results to everyone!

Result

Sender args setup demonstration: (Please set up by yourself according to your hobbies)


Send Settings. png

Acceptance program args setup demonstration: (Please set up according to your hobbies)


Accept settings. png

I used the above sender to send an Error log message
Accept only the results of Error severity:


error.png

Accept the results of procedures with severity of info and warn:


warn info.png

Accept the results of all seriousness procedures:


all.png

Very clear!!! If there's something I don't understand, or you still don't understand. Comments can be explored~~

Topics: Java less