300字范文,内容丰富有趣,生活中的好帮手!
300字范文 > RabbitMQ(四):Exchange交换器--direct

RabbitMQ(四):Exchange交换器--direct

时间:2020-08-14 15:28:41

相关推荐

RabbitMQ(四):Exchange交换器--direct

内容翻译自:RabbitMQ Tutorials Java版

RabbitMQ(一):Hello World程序

RabbitMQ(二):Work Queues、循环分发、消息确认、持久化、公平分发

RabbitMQ(三):Exchange交换器--fanout

RabbitMQ(四):Exchange交换器--direct

RabbitMQ(五):Exchange交换器--topic

RabbitMQ(六):回调队列callback queue、关联标识correlation id、实现简单的RPC系统

RabbitMQ(七):常用方法说明 与 学习小结

Routing:

在上一篇博客中,我们创建了一个简单的日志系统。我们可以将日志消息广播给所有的接收者(消费者)。

在这个教程中,我们将为我们的日志系统添加一个功能:仅仅订阅一部分消息。比如,我们可以直接将关键的错误类型日志消息保存到日志文件中,还可以同时将所有的日志消息打印到控制台。

绑定(Bindings):

在之前的例子中,我们已经创建了绑定:

channel.queueBind(queueName, EXCHANGE_NAME, "");

一个绑定是建立在一个队列和一个路由器之间的关系,可以解读为:该队列对这个路由器中的消息感兴趣。

绑定可以设置另外的参数:路由键routingKey。为了避免和void basicPublish(String exchange, String routingKey, BasicProperties props, byte[] body)中的routingKey混淆,我们将这里的key称为绑定键binding key,下面的代码展示了如何使用绑定键来创建一个绑定关系:

channel.queueBind(queueName, EXCHANGE_NAME, "black");

绑定键的含义取决于路由器的类型,我们之前使用的fanout类型路由器会忽略该值。

直接路由器 (Direct Exchange):

我们之前的日志系统会将所有消息广播给所有消费者。现在我们想根据日志的严重程度来过滤日志。比如,我们想要一个程序来将error日志写到磁盘文件中,而不要将warninginfo日志写到磁盘中,以免浪费磁盘空间。

我们之前使用的fanout路由器缺少灵活性,它只是没头脑地广播消息。所以,我们用direct路由器来替换它。direct路由器背后的路由算法很简单:只有当消息的路由键routing key与队列的绑定键binding key完全匹配时,该消息才会进入该队列。

为了演示上面拗口的表述中的意思,考虑下面的设置:

上图中,直接路由器X与两个队列绑定。第一个队列以绑定键orange来绑定,第二个队列以两个绑定键blackgreen和路由器绑定。

按照这种设置,路由键为orange的消息在发布给路由器后,将会被路由到队列Q1,路由键为black或者green的消息将会路由到队列Q2。

多重绑定(Multiple bindings):

多个队列以相同的绑定键binding key绑定到同一个Exchange上,是完全可以的。按照这种方式设置的话,直接路由器就会像fanout路由器一样,将消息广播给所有符合路由规则的队列。一个路由键为black的消息将会发布到队列Q1和Q2。

发布消息:

在这个教程中,我们使用direct路由器来代替上个教程中的fanout路由器。同时,我们为日志设置严重级别,并将此作为路由键。这样,接收者(消费者)就可以选择性地接收日志消息。

首先,创建一个路由器:

channel.exchangeDeclare(EXCHANGE_NAME, "direct");

接着,发送一个消息:

channel.basicPublish(EXCHANGE_NAME, severity, null, message.getBytes());

简单起见,我们假设severity只能是infowarningerror中的一种。

消息订阅:

接收消息将会和之前的教程类似,只是我们会为每一个级别的消息来创建不同的绑定:

String queueName = channel.queueDeclare().getQueue();for(String severity : argv){channel.queueBind(queueName, EXCHANGE_NAME, severity);}

放在一块:

生产者EmitLogDirect.java的完整代码:

import com.rabbitmq.client.BuiltinExchangeType;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 {//创建连接ConnectionFactory factory = new ConnectionFactory();factory.setHost("localhost");Connection connection = factory.newConnection();Channel channel = connection.createChannel();//声明路由器和路由器的类型channel.exchangeDeclare(EXCHANGE_NAME, BuiltinExchangeType.DIRECT);String severity = "info";String message = ".........i am msg.........";//发布消息channel.basicPublish(EXCHANGE_NAME, severity, null, message.getBytes("UTF-8"));System.out.println(" [x] Sent '" + severity + "':'" + message + "'");channel.close();connection.close();}}

消费者ReceiveLogsDirect.java的完整代码如下:

import com.rabbitmq.client.*;import java.io.IOException;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, BuiltinExchangeType.DIRECT);//声明队列String queueName = channel.queueDeclare().getQueue();//定义要监听的级别String[] severities = {"info", "warning", "error"};//根据绑定键绑定for (String severity : severities) {channel.queueBind(queueName, EXCHANGE_NAME, severity);}System.out.println(" [*] Waiting for messages. To exit press CTRL+C");Consumer consumer = new DefaultConsumer(channel) {@Overridepublic void handleDelivery(String consumerTag, Envelope envelope,AMQP.BasicProperties properties, byte[] body) throws IOException {String message = new String(body, "UTF-8");System.out.println(" [x] Received '" + envelope.getRoutingKey() + "':'" + message + "'");}};channel.basicConsume(queueName, true, consumer);}}

现在可以进行测试了。首先,启动一个消费者实例(ReceiveLogsDirect.java),然后将其中的要监听的级别改为String[] severities = {"error"};,再启动另一个消费者实例。此时,这两个消费者都开始监听了,一个监听所有级别的日志消息,另一个监听error日志消息。

然后,启动生产者(EmitLogDirect.java),之后将String severity = "info";中的info,分别改为warningerror后运行。

这样,就可以在控制台看到如下输出:

//生产者[x] Sent 'warning':'.........i am msg.........'[x] Sent 'info':'.........i am msg.........'[x] Sent 'error':'.........i am msg.........'//消费者1[*] Waiting for messages. To exit press CTRL+C[x] Received 'info':'.........i am msg.........'[x] Received 'error':'.........i am msg.........'[x] Received 'warning':'.........i am msg.........'//消费者2[*] Waiting for messages. To exit press CTRL+C[x] Received 'error':'.........i am msg.........'

说明:

①与原文略有出入,如有疑问,请参阅原文

②原文均是编译后通过javacp命令直接运行程序,我是在IDE中进行的,相应的操作做了修改。

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。