5 Topics
In the previous tutorial, we improved the log system. In order to solve the brainless broadcast of fanout exchange
b19a9dab5264c86c7ab83272db11c361---, we replaced it with direct
, thus realizing selective log reception.
Although using the direct exchange improves the system, it has limitations - it cannot route messages based on multiple criteria.
In our logging system, we want to subscribe to logs based on both log level and log source. You may know this concept from the syslog unix tool, which routes logs based on their level and device.
This would allow a lot of flexibility - we might want to listen to critical error logs from 'cron' and all logs from 'kern'.
To implement this functionality in a logging system, we need to learn a bit more complicated topic exchange.
Topic exchange
A message sent to a topic exchange cannot use random routing_key
- it must be a set of words separated by .
. Can be any word, but is usually related to some characteristic of the message. These routing key
are all legal: "stock.usd.nyse", "nyse.vmw", "quick.orange.rabbit". There is no limit to the number of words in routing key
, but the maximum length cannot exceed 255 bytes.
The format of binding key
is the same. The processing logic of topic exchange
direct
is similar to that of ---5c5d9433a83990435876f9af6edd418f------by specifying routing key
the message sent will be distributed to all matching binding key
on the queue.
- (asterisk)* represents a specific word
- (pound sign)# represents 0 or more words
The following example can easily explain this:
In the figure, we will send some messages that describe the characteristics of the animal. The message will use routing key
containing three words (separated by two dots). The first word describes speed, the second describes color, and the third describes variety: "<speed>.<colour>.<species>"
.
创建三个绑定: Q1
"*.orange.*"
, Q2
"*.*.rabbit"
"lazy.#"
bingding key
.
The bindings above are summarized as follows:
-
Q1
Interested in all yellow animals -
Q2
Want to subscribe to all rabbits and all lazy animals
routing key
"quick.orange.rabbit"
will be sent to both queues at the same time,
"lazy.orange.elephant"
messages are also sent to both queues.另外, "quick.orange.fox"
Q1
, "lazy.brown.fox"
会发给Q2
, "lazy.pink.rabbit"
Q2
once, even if there are two bindings matching Q2
, "quick.brown.fox"
not match any binding, so it will be discarded.
What if we break the rules and send a message with one or four words (as routing key
), like “orange”
or “quick.orange.male.rabbit”
? Of course, these messages will not match any binding
and will be discarded.
However, for "lazy.orange.male.rabbit"
, although it has four words, will still match the last bingding
(lazy.#) and send to Q2
Topic exchange
Topic exchange is very powerful, it can be made to work like any other exchange
When a queue is bound by
binding key
"#" - he will receive all messages, ignorerouting key
- just like fanout exchangeWhen special characters: "*" and "#" are not present in the binding, topic exchange works like direct exchange
Putting it all together
We will use topic exchange in our logging system. We assume that the routing key of the log consists of two words: "<device>.<level>"
The code is almost the same as the previous tutorial
EmitLogTopic.java source code:
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;
public class EmitLogTopic {
private static final String EXCHANGE_NAME = "topic_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, "topic");
String routingKey = getRouting(argv);
String message = getMessage(argv);
channel.basicPublish(EXCHANGE_NAME, routingKey, null, message.getBytes("UTF-8"));
System.out.println(" [x] Sent '" + routingKey + "':'" + message + "'");
}
}
//..
}
ReceiveLogsTopic.java source code:
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;
import com.rabbitmq.client.DeliverCallback;
public class ReceiveLogsTopic {
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();
channel.exchangeDeclare(EXCHANGE_NAME, "topic");
String queueName = channel.queueDeclare().getQueue();
if (argv.length < 1) {
System.err.println("Usage: ReceiveLogsTopic [binding_key]...");
System.exit(1);
}
for (String bindingKey : argv) {
channel.queueBind(queueName, EXCHANGE_NAME, bindingKey);
}
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 -> { });
}
}
Compile and run the sample code, remember to introduce the classpath as in tutorial 1 - windows use %CP%.
Compile:
javac -cp $CP ReceiveLogsTopic.java EmitLogTopic.java
receive log messages
java -cp $CP ReceiveLogsTopic "#"
Receive all log messages for device "kern"
java -cp $CP ReceiveLogsTopic "kern.*"
Or only care about "critical" level logs
java -cp $CP ReceiveLogsTopic "*.critical"
Multiple bindings can be created
java -cp $CP ReceiveLogsTopic "kern.*" "*.critical"
Use routing key
"kern.critical" to send log messages:
java -cp $CP EmitLogTopic "kern.critical" "A critical kernel error"
Have fun with your program. Note that the code does not set a routing key or binding key, you need to specify it through parameters when playing.
(Complete source code reference: EmitLogTopic.java and ReceiveLogsTopic.java )
The next article, in Tutorial 6 , will introduce how to use round-trip messages to implement Remote Procedure Call (Remote Procedure Call)
【Recommended reading】
RabbitMQ Tutorial 4. Routing
RabbitMQ Tutorial 3. Publish/Subscribe
RabbitMQ Tutorial 2. Work Queue (Work Queue)
RabbitMQ Tutorial 1. "Hello World"
Freemarker Tutorial (1) - Template Development Manual
The downloaded attachment name is always garbled? It's time for you to read the RFC document!
Explain MySQL priority queue in simple terms (the order by limit problem you will definitely step on)
It is not easy to code words, please like, follow and share.
Search: [Java class representative], follow the official account, update every day, and get more Java dry goods in time.
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。