5.主题模式
在路由模式中,使用Direct交换机,从而可以选择性接收日志。
虽然使用Direct交换机改进了我们的系统,但它不能基于多个标准进行路由。
这是缺乏灵活性的,要在日志系统中实现这一点,我们需要了解更复杂的Topic交换机。
主题交换机 Topic exchange
发送到Topic交换机的消息,它的的routingKey,必须是由点分隔的多个单词。单词可以是任何东西,但通常是与消息相关的一些特性。
routingKey可以有任意多的单词,最多255个字节。
bindingKey也必须采用相同的形式。Topic交换机的逻辑与直连交换机类似——使用特定routingKey发送的消息将被传递到所有使用匹配bindingKey绑定的队列。bindingKey有两个重要的特殊点:
*
可以通配单个单词。#
可以通配零个或多个单词。
如上图中,将routingKey设置为"quick.orange.rabbit
"的消息将被发送到两个队列。消息 "lazy.orange.elephant
“也发送到它们两个。另外”quick.orange.fox
“只会发到第一个队列,”lazy.brown.fox
“只发给第二个。”lazy.pink.rabbit
“将只被传递到第二个队列一次,即使它匹配两个绑定。”quick.brown.fox
"不匹配任何绑定,因此将被丢弃。
生产者
public class Test1 {
public static void main(String[] args) throws Exception {
ConnectionFactory f = new ConnectionFactory();
f.setHost("192.168.64.140");
f.setPort(5672);
f.setUsername("admin");
f.setPassword("admin");
Connection c = f.newConnection();
Channel ch = c.createChannel();
//参数1: 交换机名
//参数2: 交换机类型
ch.exchangeDeclare("topic_logs", BuiltinExchangeType.TOPIC);
while (true) {
System.out.print("输入消息: ");
String msg = new Scanner(System.in).nextLine();
if ("exit".contentEquals(msg)) {
break;
}
System.out.print("输入routingKey: ");
String routingKey = new Scanner(System.in).nextLine();
//参数1: 交换机名
//参数2: routingKey, 路由键,这里我们用日志级别,如"error","info","warning"
//参数3: 其他配置属性
//参数4: 发布的消息数据
ch.basicPublish("topic_logs", routingKey, null, msg.getBytes());
System.out.println("消息已发送: "+routingKey+" - "+msg);
}
c.close();
}
}
消费者
public class Test2 {
public static void main(String[] args) throws Exception {
ConnectionFactory f = new ConnectionFactory();
f.setHost("192.168.64.140");
f.setUsername("admin");
f.setPassword("admin");
Connection c = f.newConnection();
Channel ch = c.createChannel();
ch.exchangeDeclare("topic_logs", BuiltinExchangeType.TOPIC);
//自动生成对列名,
//非持久,独占,自动删除
String queueName = ch.queueDeclare().getQueue();
System.out.println("输入bindingKey,用空格隔开:");
String[] a = new Scanner(System.in).nextLine().split("\\s");
//把该队列,绑定到 topic_logs 交换机
//允许使用多个 bindingKey
for (String bindingKey : a) {
ch.queueBind(queueName, "topic_logs", bindingKey);
}
System.out.println("等待接收数据");
//收到消息后用来处理消息的回调对象
DeliverCallback callback = new DeliverCallback() {
@Override
public void handle(String consumerTag, Delivery message) throws IOException {
String msg = new String(message.getBody(), "UTF-8");
String routingKey = message.getEnvelope().getRoutingKey();
System.out.println("收到: "+routingKey+" - "+msg);
}
};
//消费者取消时的回调对象
CancelCallback cancel = new CancelCallback() {
@Override
public void handle(String consumerTag) throws IOException {
}
};
ch.basicConsume(queueName, true, callback, cancel);
}
}
6.RPC模式
该模式不常使用,也较为复杂,了解即可.
RPC模式顾名思义也就是远程调用模式.
RabbitMQ去搭建一个RPC系统:一个客户端和一个可以升级(扩展)的RPC服务器
总结:
RPC的工作方式是这样的:
- 对于RPC请求,客户端发送一条带有两个属性的消息:replyTo,设置为仅为请求创建的匿名独占队列,和correlationId,设置为每个请求的惟一id值。
- 请求被发送到rpc_queue队列。
- RPC工作进程(即:服务器)在队列上等待请求。当一个请求出现时,它执行任务,并使用replyTo字段中的队列将结果发回客户机。
- 客户机在回应消息队列上等待数据。当消息出现时,它检查correlationId属性。如果匹配请求中的值,则向程序返回该响应数据。