今天来学习RabbitMQ的消息分发策略。
在RabbitMQ札记-RabbitMQ入门一文中,我们曾学习过RabbitMQ的概念模型,其中就介绍过消息分发策略。
Exchange表示交换器,用来接收生产者发送的消息并将这些消息路由给队列。从图中可以看出,Procuder发布的Message进入了Exchange。Exchange通过Routing key与Queue绑定在一起。通过Routing key, RabbitMQ可以得知应该把这个Message放到哪个Queue里。Exchange分发消息时根据类型的不同分发策略有区别,目前共五种类型:fanout、direct、topic、headers、x-delayed-message。
fanout。每个发到 fanout 类型交换器的消息都会分到所有绑定的队列上去。
direct。如果Routing key匹配, 那么Message就会被传递到相应的Queue中。比如key可以传递到Routing key为key的Queue。
topic。对Routing key进行模式匹配,比如key*可以传递到Routing key为key1、key2、key3的Queue。
为了理解消息分发策略,我们将建立一个简单的日志系统。它将包含两种程序,一个Producer和两个Consumer。Producer将发送日志消息,Consumer将接收并打印消息。
fanoutx
在前面的文章中,每个Message都是deliver给一个Consumer。今天我们学习如何将一个Message传递给多个Consumer,这种模式被称为“发布/订阅”模式。
分发策略中的fanout就是广播模式,每个发到 fanout 类型Exchange的消息都会发到所有绑定的队列上去。让我们创建一个这种类型的Exchange,并将其命名为logs:
channel.exchangeDeclare(“logs”,“fanout”);
现在,我们可以发布Message到名为logs的Exchange了:
channel.basicPublish("logs","",null,message.getBytes());
临时队列
截至现在,我们用的queue都是有名字的,如testQueue。但是对于我们将要构建的日志系统,并不需要有名字的queue。当我们不给queueDeclare()提供参数时,将用一个自动生成的名称创建一个非持久的,独占的自动删除队列:
String queueName = channel.queueDeclare().getQueue();
此时queueName是一个随机的队列名称,它可能看起来像amq.gen-JzTY20BRgKO-HjmUJj0wLg。
绑定
我们已经学习了如何创建fanout 类型的Exchange和临时队列。现在我们需要将两者绑定起来。
channel.queueBind(queueName,"logs","");
最终版本
Producer.java
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;
import java.io.IOException;
import java.util.concurrent.TimeoutException;
public class Producer {
private final static String EXCHANGE_NAME = "logs";
public static void main(String[] args) throws IOException, TimeoutException {
// 创建一个到服务器的连接
ConnectionFactory factory = new ConnectionFactory();
factory.setUsername("yst");
factory.setPassword("yst");
factory.setHost("192.168.17.64");
Connection conn = factory.newConnection();
Channel channel = conn.createChannel();
//发布消息到我们的exchange,而不是队列
channel