RabbitMQ系列
来源:互联网 发布:下载软件管理器 编辑:程序博客网 时间:2024/05/10 02:52
本文出自于EumJi个人博客,仅限于学习用途的转载,转载请注明出处http://www.eumji025.com/article/details/258665
在上一篇教程发布和订阅中,我们构建了一个能向消费者广播信息的例子。
在本教程中,我们将为其添加一个功能 - 我们将可以仅订阅一部分消息。例如,我们将能够仅将关键的错误消息引导到日志文件(以节省磁盘空间),同时仍然能够在控制台上打印所有日志消息。
绑定
在之前的例子中,我们已经创建了绑定。绑定是exchanges和queue之间的关系。绑定可以使用额外的参数。为了避免与basic_publish 参数混淆,我们将其称为 routingKey。如下代码
channel.queueBind(queue, EXCHANGE_NAME, "routing_key");
由于之前我们使用的是fanout,fanout会忽略routingKey的存在,与所有的进行匹配。后面我们会出一篇讲解几种exchanges类型差异。
direct exchanges
我们从上上一篇教程[发布和订阅]向所有消费者广播所有消息。我们希望将其扩展为允许基于其严重性过滤消息。例如,我们可能需要一个将error日志消息写入磁盘的程序,而不会把warning或info级别的消息记录上的磁盘空间。
如果使用fanout类型的exchanges,不能给我们很大的灵活性 - 它只能没有选择地广播信息。
我们将使用direct exchanges。direct exchange背后的路由算法很简单 - 消息传递到绑定密钥与消息的路由密钥完全匹配的队列 。如下图所示:
在上述设置中direct类型的交换机通过routingKey为orange的和Q1绑定,routingKey为black,green的绑定Q2,联想我们上面的设定,我们可以把Q1假设为记录错误日志的队列。当然我们也可以使用一个routingKey绑定多个队列这都是可行的,如下图所示
案例展示
发布者
public class RoutingPublish { private static Logger logger = LoggerFactory.getLogger(RoutingPublish.class); private static final String EXCHANGE_NAME = "routing_worker"; public static void main(String[] args) throws IOException, TimeoutException { ConnectionFactory factory = new ConnectionFactory(); factory.setHost("localhost"); Connection connection = null; Channel channel = null; try { connection = factory.newConnection(); channel = connection.createChannel(); //设置为DIRECT channel.exchangeDeclare(EXCHANGE_NAME, BuiltinExchangeType.DIRECT); for (int i = 0; i < 10; i++) { String message = getMessage(); String severity = getSeverity(); System.out.println("publish worker will send "+severity+" message:"+message); channel.basicPublish(EXCHANGE_NAME,severity,null,getMessage().getBytes("UTF-8")); } } catch (IOException e) { logger.error("connect io exception"); e.printStackTrace(); } catch (TimeoutException e) { logger.error("connect timeout exception"); e.printStackTrace(); }finally { channel.close(); connection.close(); } } //时间戳模拟消息 private static String getMessage() { try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } return String.valueOf(System.currentTimeMillis()); } //模拟安全类型,随机 private static String getSeverity() { int num = new Random().nextInt(3); switch (num){ case 0:return "info"; case 1:return "warning"; case 2:return "error"; } return null; }
和之前的推送差不多,只是我们在basicPublish时绑定了具体的routingKey。
订阅者
public class RoutingReceive extends Thread{ private static Logger logger = LoggerFactory.getLogger(RoutingReceive.class); private static final String EXCHANGE_NAME = "routing_worker"; private String workerName; private String security; public RoutingReceive(String workerName,String security){ this.security = security; this.workerName = workerName; } @Override public void run() { ConnectionFactory factory = new ConnectionFactory(); factory.setHost("localhost"); Connection connection; Channel channel; try { connection = factory.newConnection(); channel = connection.createChannel(); channel.exchangeDeclare(EXCHANGE_NAME, BuiltinExchangeType.DIRECT); String queue = channel.queueDeclare().getQueue(); channel.queueBind(queue, EXCHANGE_NAME, security); System.out.println("receive worker wait message!!!"); Consumer consumer = new DefaultConsumer(channel) { @Override public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException { super.handleDelivery(consumerTag, envelope, properties, body); String message = new String(body, 0, body.length, "UTF-8"); System.out.println(workerName+" receive "+security+" message :" + message); } }; channel.basicConsume(queue, true, consumer); } catch (IOException e) { e.printStackTrace(); } catch (TimeoutException e) { e.printStackTrace(); } } //模拟三个线程,分别接受不同类型的消息。 public static void main(String[] args) { RoutingReceive error = new RoutingReceive("error_worker","error"); error.start(); RoutingReceive info = new RoutingReceive("info_worker","info"); info.start(); RoutingReceive warning = new RoutingReceive("warning_worker","warning"); warning.start(); }}
测试结果
首先运行发布者routingPublish,随机出现三种类型信息,具体如下图
publish worker will send info message:1495015315377publish worker will send error message:1495015317379publish worker will send warning message:1495015319381...
然后我们运行订阅者,如下图
info_worker receive info message :1495015401669info_worker receive info message :1495015403672warning_worker receive warning message :1495015405673warning_worker receive warning message :1495015407674warning_worker receive warning message :1495015409676error_worker receive error message :1495015411677...
结语
从上面的演示中我们可以将消息分类进行推送,就可以使用专门的线程接受error信息并将其记录。
与发布订阅的fanout主题相比,direct模式则限制则更大,routingkey使得exchange和queue的绑定非常 的细腻。
本文主要参照了RabbitMQ的官方教程并进行修改而成。
与君共勉!!!
参考文章
RabbitMQ-direct-java
源码地址
RabbitMQ-routing
- RabbitMQ 系列
- RabbitMQ系列
- RabbitMQ系列—RabbitMQ介绍
- RabbitMQ系列—RabbitMQ 安装
- RabbitMQ系列之RabbitMQ单机安装
- RabbitMQ学习系列 : RabbitMQ安装与配置
- RabbitMQ学习系列 : C# 如何使用 RabbitMQ
- RabbitMQ系列—RabbitMQ 代码演示
- python系列之 RabbitMQ -- Routing
- python系列之 RabbitMQ -- TOPICS
- python系列之 RabbitMQ - RPC
- RabbitMQ系列(一):Windows下RabbitMQ安装及入门
- 10046--- RabbitMQ系列(一):Windows下RabbitMQ安装及入门
- 初识RabbitMQ系列之三:.net 如何使用RabbitMQ
- RabbitMQ系列(一):Windows下RabbitMQ安装及入门
- RabbitMQ 系列——1.初始
- RabbitMQ系列三 (深入消息队列)
- python系列之 RabbitMQ - hello world
- 线程安全和可重入函数
- apk反编译教程
- freebuf上一篇关于waf绕过的介绍
- 多种单例模式实现方法详解——java代码
- 开篇第一章<简要IOT技术栈分析>
- RabbitMQ系列
- kaldi006 -- 构图
- Hdu2018 母牛的故事
- 如何解决wireshark抓包大于mtu的问题
- 关于网页消息提示音问题解决与实现
- C++容器vector的常用成员函数
- Linux(centos7)安装redis及第一个helloWorld
- 图的邻接表表示法及遍历
- 反射-通过反射写一个通用的设置某个对象的某个属性为指定的值