系统拆分解耦利器之消息队列---RabbitMQ-主题(Topic)
来源:互联网 发布:上海程序员培训机构 编辑:程序博客网 时间:2024/05/19 00:14
[一曲广陵不如晨钟暮鼓]
本文,我们来介绍RabbitMQ中的Topic类型的exchange。在正式开始之前,我们假设RabbitMQ服务已经启动,运行端口为5672,如果各位看官有更改过默认配置,那么就需要修改为对应端口,保持一致即可。
准备工作:
操作系统:window 7 x64
其他软件:eclipse mars,jdk7,maven 3
--------------------------------------------------------------------------------------------------------------------------------------------------------
主题(Topic)
在上文中,我们已经使用点对点的direct方式替换掉广播式的fanout模式,从而改进了日志系统。尽管这种点对点的direct方式已经成功的提升了系统的灵活性,但是其还是有限制的。那就是其不能基于多参数的路由。
在我们构建的日志系统中,我们想要订阅的方式不只是基于日志级别,并且还需要按照日志的生产源进行订阅。你可能从unix日志工具:syslog当中已经了解到这个改变,这种路由方式同时基于日志的级别和产生日志的生产源(auth/cron/kern)。
通过这种方式,能够给我们收集系统日志提供极大的灵活性。举个例子:比如我们想监听的只是非常严重的错误,并且错误源是“cron”,在这个基础之上,我们还需要收集来自“kern”的所有日志。
为了实现上面的这个需求,下面来介绍一下RabbitMQ中更加复杂的toipc类型的exchange的概念及使用方法吧。
主题类型的交换器(Topic exchange)
在向topic类型的exchange发送消息时,不能够随意的设定routing_key。其必须是一个通过句号分割的单词的列表。至于单词,可以是任意的有意义的或者无意义的均,但通常情况下,这个单词都暗示了消息的某些特性。举个例子:“stockl.usd.nyse”,“nyse.vmw”,“quick.orange.rabbit”等等。单词格式不做任何的限制,但是其长度最多只能有255个字节(byte)。
同时,binding key必须是与消息发送者使用的binding key的格式保持一致。这里topic后台处理逻辑和前文我们介绍的点对点的direct处理逻辑非常类似。一个带有特定binding key的消息将会被投递到所有的与之匹配的队列当中。但是,请注意以下两个特殊符号:
- *(star):只能匹配一个单词。(0个或者多个都不可以)
- #(hash):能够匹配大于等于零个单词。
这个概念可以很容易的使用下面这张图进行解释:
在这幅图中,我们将会发送能够描述动物特性的消息。消息将带有一个routing key(有两个间隔点)。第一个单词用以描述速度。第二个单词用以描述颜色。第三个单词用以描述种类。合起来的格式就是:“<speed>.<colour>.<species>”。
我们创建三个绑定关系:
- Q1:【*orange.*】
- Q2:【*.*.rabbit】,【lazy.#】
- 当一个队列的binding key为“#”时,其能够接收到所有的消息,就像routing key不存在一样。
- 当一个队列的binding key中不使用“#”或者“*”时,其表现出的特性与direct类型表现的特性完全一致。
package com.csdn.ingo.rabbitmq_1;import java.io.IOException;import java.util.Date;import java.util.Random;import java.util.UUID;import com.rabbitmq.client.Channel;import com.rabbitmq.client.Connection;import com.rabbitmq.client.ConnectionFactory;public class EmitLogTopic {// 队列名称private final static String EXCHANGE_NAME = "topic_logs";public static void main(String[] args) throws IOException {// 创建连接和频道ConnectionFactory factory = new ConnectionFactory();factory.setHost("localhost");Connection connection = factory.newConnection();Channel channel = connection.createChannel();// 声明队列channel.exchangeDeclare(EXCHANGE_NAME, "topic");String[] routing_keys = new String[] { "kernel.info", "cron.warning", "auth.info", "kernel.critical" };for (String routing_key : routing_keys) {String message = UUID.randomUUID().toString();channel.basicPublish(EXCHANGE_NAME, routing_key, null, message.getBytes());System.out.println("[x] Sent routing_key:" + routing_key + ",message:" + message);}// 关闭频道和资源channel.close();connection.close();}}3.创建ReceiveLogsTopicForCritical文件,具体内容如下:
package com.csdn.ingo.rabbitmq_1;import java.io.IOException;import java.util.Random;import com.rabbitmq.client.Channel;import com.rabbitmq.client.Connection;import com.rabbitmq.client.ConnectionFactory;import com.rabbitmq.client.ConsumerCancelledException;import com.rabbitmq.client.QueueingConsumer;import com.rabbitmq.client.ShutdownSignalException;public class ReceiveLogsTopicForCritical {private final static String EXCHANGE_NAME = "topic_logs";public static void main(String[] args)throws IOException, ShutdownSignalException, ConsumerCancelledException, InterruptedException {ConnectionFactory factory = new ConnectionFactory();factory.setHost("localhost");Connection conn = factory.newConnection();Channel channel = conn.createChannel();channel.exchangeDeclare(EXCHANGE_NAME, "topic");String queueName = channel.queueDeclare().getQueue();channel.queueBind(queueName, EXCHANGE_NAME, "*.critical");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:" +routingkey+",message:"+ message);}}}4.创建ReceiveLogsTopicForKernel文件,具体内容如下:
package com.csdn.ingo.rabbitmq_1;import java.io.IOException;import java.util.Random;import com.rabbitmq.client.Channel;import com.rabbitmq.client.Connection;import com.rabbitmq.client.ConnectionFactory;import com.rabbitmq.client.ConsumerCancelledException;import com.rabbitmq.client.QueueingConsumer;import com.rabbitmq.client.ShutdownSignalException;public class ReceiveLogsTopicForKernel {private final static String EXCHANGE_NAME = "topic_logs";public static void main(String[] args)throws IOException, ShutdownSignalException, ConsumerCancelledException, InterruptedException {ConnectionFactory factory = new ConnectionFactory();factory.setHost("localhost");Connection conn = factory.newConnection();Channel channel = conn.createChannel();channel.exchangeDeclare(EXCHANGE_NAME, "topic");String queueName = channel.queueDeclare().getQueue();channel.queueBind(queueName, EXCHANGE_NAME, "kernel.*");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:" +routingkey+",message:"+ message);}}}5.测试方法:首先运行两个接收方程序,在运行发送者程序,观察控制台输出即可。
-------------------------------------------------------------------------------------------------------------------------------------------------------
至此,系统拆分解耦利器之消息队列---RabbitMQ-主题(Topic) 结束
参考资料:
官方文档:http://www.rabbitmq.com/tutorials/tutorial-five-java.html
- 系统拆分解耦利器之消息队列---RabbitMQ-主题(Topic)
- 系统拆分解耦利器之消息队列---RabbitMQ-Helloworld
- 系统拆分解耦利器之消息队列---RabbitMQ-路由
- 系统拆分解耦利器之消息队列---RabbitMQ-Configuration
- 系统拆分解耦利器之消息队列---RabbitMQ-工作队列
- 系统拆分解耦利器之消息队列---RabbitMQ安装配置
- 系统拆分解耦利器之消息队列---RabbitMQ-发布/订阅
- 系统拆分解耦利器之消息队列---RabbitMQ-RPC远程调用
- 系统拆分解耦利器之消息队列---RabbitMQ-Persistence Configuration
- (八)RabbitMQ消息队列-通过Topic主题模式分发消息
- RabbitMQ学习之主题topic(java)
- RabbitMQ消息分发模式----"Topic"主题模式
- RabbitMQ消息分发模式----"Topic"主题模式
- RabbitMQ (消息队列)专题学习06 Topic
- RabbitMQ学习(五)之主题topic(java)
- RabbitMQ的Exchange 模式之topic(主题模式)
- RabbitMQ消息队列(六):使用主题进行消息分发
- RabbitMQ消息队列(六):使用主题进行消息分发
- java服务器编程——log4j日志
- MySQL(十二)存储过程和函数的操作
- Toolbar自定义布局
- swift函数
- windows下桌面回收站图标的去除方法
- 系统拆分解耦利器之消息队列---RabbitMQ-主题(Topic)
- 图片懒加载解决方案 lazyload.js
- BroadcastReceiver基本用法
- 在本地安装Ik analyzer 兼容lucene 4.X版本
- Visual Stdio C++ 编译器 编译 (GSL) GNU Scientific Library 的方法介绍(3)
- Effective Modern C++ 条款20 把std::weak_ptr当作类似std::shared_ptr的、可空悬的指针使用
- Android仿淘宝购物车
- 开启我的编程人生
- IOS下拉菜单