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:
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
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
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)
Acceptance program args setup demonstration: (Please set up according to your hobbies)
I used the above sender to send an Error log message
Accept only the results of Error severity:
Accept the results of procedures with severity of info and warn:
Accept the results of all seriousness procedures:
Very clear!!! If there's something I don't understand, or you still don't understand. Comments can be explored~~