Routing
上一讲所介绍的扇形交换,是将交换机将消息分发给所有的队列,而现在这个路由机制则是对这一部分的进一步优化。
下面将对这一一介绍:
Bindings
在之前的例子中,我们创建交换机和队列之间的绑定关系是这样的:channel.queueBind(queueName, EXCHANGE_NAME, "");大家可以看到,第三个参数“ ”,其实就是routingkey,所以现在可以这样写:
channel.queueBind(queueName, EXCHANGE_NAME, "black");这也就意味着,如今交换关系的绑定,取决于“black”交换的类型,而之前的fanout exchanges忽视了这一点
Direct exchange
那一个日志系统来说吧,之前fanout exchanges是将所有日志信息发送给所有consumers,这样称作广播式。而现在,我们想要consumers1接收error消息,consumers2接收warning消息等等
这样我们便需要这样一个路由,来过滤这些消息,这样也被称作订阅式。
如图所示:橙色消息将被发送给Q1,而黑色和绿色消息将发送给Q2,其他消息将被丢弃。
Multiple bindings
用同样的绑定值作为路由键也是完全可以的,针对一些场景也会用到这样设置。
Emitting logs
现在改由这订阅的方式来创建日志系统channel.exchangeDeclare(EXCHANGE_NAME, "direct");
channel.basicPublish(EXCHANGE_NAME, severity, null, message.getBytes());
severity--可以为warn、error、info等关键字
Subscribing
String queueName = channel.queueDeclare().getQueue(); for(String severity : argv){ channel.queueBind(queueName, EXCHANGE_NAME, severity); }整体的结构:
package logs;
import java.util.Arrays;
import com.rabbitmq.client.ConnectionFactory;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.Channel;
public class EmitLogDirect {
private static final String EXCHANGE_NAME = "direct_logs";
public static void main(String[] argv) throws Exception {
argv = new String[1];
argv[0]="warning";
ConnectionFactory factory = new ConnectionFactory();
factory.setHost("localhost");
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());
System.out.println(" [x] Sent '" + severity + "':'" + message + "'");
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();
}
}
package logs;
import com.rabbitmq.client.ConnectionFactory;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.QueueingConsumer;
public class ReceiveLogsDirect {
private static final String EXCHANGE_NAME = "direct_logs";
public static void main(String[] argv) throws Exception {
// argv = new String[3];
// argv[0]="error";
// argv[1]="warning";
// argv[2]="info";
argv = new String[1];
argv[0]="error";
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.print(severity+"、");
}
System.out.println();
System.out.println(" [*] Waiting for messages. To exit press CTRL+C");
QueueingConsumer consumer = new QueueingConsumer(channel);
channel.basicConsume(queueName, true, consumer);
while (true) {
QueueingConsumer.Delivery delivery = consumer.nextDelivery();
String message = new String(delivery.getBody());
String routingKey = delivery.getEnvelope().getRoutingKey();
System.out.println(" [x] Received '" + routingKey + "':'" + message + "'");
}
}
}
结果:
[x] Sent 'warning':'Hello World!'
[x] Sent 'error':'Hello World!'
[x] Sent 'info':'Hello World!'
error、warning、info、
[*] Waiting for messages. To exit press CTRL+C
[x] Received 'error':'Hello World!'
[x] Received 'info':'Hello World!'
[x] Received 'warning':'Hello World!'
error、
[*] Waiting for messages. To exit press CTRL+C
[x] Received 'error':'Hello World!'