In order to facilitate better communication, you can pay attention to the public number: Java class representative , every day, waiting for you!
4 Routing
In the last tutorial we created a simple logging system. Log messages can be broadcast to multiple recipients.
In this tutorial, we'll add a new feature to it - making it possible to subscribe to a certain subset (subset) of messages individually. For example, we only write critical errors to disk files (saving only the critical error log to save disk), while still outputting all logs to the terminal.
Bindings
In the previous example, we have created the binding, you may remember the following code:
channel.queueBind(queueName, EXCHANGE_NAME, "");
A binding is a relationship between an exchange and a queue. It can be simply understood as: this queue is interested in messages from this exchange.
Bindings can have a routingKey
parameter. In order to avoid confusion with the parameters of the basic_publish
method (Class Representative Note: The routingKey
parameter of the Channel#queueBind(String queue, String exchange, String routingKey) method is used to implement the binding relationship, and The routingKey of the Channel#basicPublish(String exchange, String routingKey, BasicProperties props, byte[] body) method is used to route messages), we will call it binding key
:
channel.queueBind(queueName, EXCHANGE_NAME, "black");
The meaning of the binding key depends on the type of exchange. The swap of the type we used earlier fanout
ignores its value.
Direct exchange
The logging system from our previous tutorial broadcasts all messages to all consumers. We want to be able to filter based on the urgency of the message. For example, you might want an application to only log critical errors to disk and not log warnings and informational log messages to save disk.
The fanout exchange we used before was not very flexible - it was just a no-brainer broadcast.
direct exchange
替代, direct exchange
简单——消息会进入那个队列的binding key
与消息的routing key
Exactly matching queue.
To illustrate this point, consider the following setup:
direct exchange X
设置中,可以看到---f980a0b2a957d74c736951b0a59913c1---绑定了两个queue
. Q1
使用---37f7abcfd273ed6de5721ed2e8772c2b orange
binding key
, Q2
has two bindings, one is black
and the other is green
.
在该设置下, orange
359f74d422ca3ab3ab658184ee632cf4---作为routing key
的消息, exchange
后将被路由到Q1
.使用black
or green
messages as routing key
will be routed to Q2
. Other messages will be discarded.
Multiple bindings
Using the same binding key
to bind to multiple queue
is perfectly legal. In the image above, we bind X
and Q1
via black
as binding key
. In this way, direct exchange
will broadcast the message to all matching queues like fanout
, (class representative note: fanout
is a no-brainer broadcast to all queue
, direct
are sent to all matching queue
).
Emitting logs
We will apply this model to the logging system. Use direct exchange
instead of fanout
to send the message. We will provide the log level as routing key
. This way, the receiving program can receive messages according to the level he wants. Let's take a look at the sending log first.
As before, first create a exchange
:
channel.exchangeDeclare(EXCHANGE_NAME, "direct");
Then you can send the message:
channel.basicPublish(EXCHANGE_NAME, severity, null, message.getBytes());
For simplicity, we assume log levels are divided into: 'info', 'warning', 'error'.
Subscribing
The receiver message program works as in the previous tutorial, with one exception, we need to create bindings for the log levels of interest.
String queueName = channel.queueDeclare().getQueue();
for(String severity : argv){
channel.queueBind(queueName, EXCHANGE_NAME, severity);
}
Putting it all together
EmitLogDirect.java complete code:
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 complete code:
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 -> { });
}
}
Compile as before (refer to section 1 for compilation and classpath settings). For convenience, we use the environment variable $CP (%CP% under Windows) as the classpath when running the example.
javac -cp $CP ReceiveLogsDirect.java EmitLogDirect.java
If you only want to save 'warning' and 'error' (don't want 'info') level logs to a file, just open a terminal and type:
java -cp $CP ReceiveLogsDirect warning error > logs_from_rabbit.log
If you want to see all the messages on the screen, open a new terminal and type:
java -cp $CP ReceiveLogsDirect info warning error
# => [*] Waiting for logs. To exit press CTRL+C
Finally, as an example, send an 'error' level log message:
java -cp $CP EmitLogDirect error "Run. Run. Or it will explode."
# => [x] Sent 'error':'Run. Run. Or it will explode.'
(See (EmitLogDirect.java source) and (ReceiveLogsDirect.java source) for the complete source code)
Continue to tutorial 5 to learn how to listen for messages based on patterns.
【Recommended reading】
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, and get more Java dry goods in time.
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。