RabbitMQ消息分发模式----"Topic"主题模式

来源:互联网 发布:软件项目汇报 模板 编辑:程序博客网 时间:2024/05/21 16:56

前面虽然有Direct类型和Fanout的转换器。但它们仍然有一定的局限性——不能根据多重条件进行路由选择。

Topic exchange(主题转发器)

发送给主题转发器的消息不能是任意设置的选择键,必须是用小数点隔开的一系列的标识符。这些标识符可以是随意,但是通常跟消息的某些特性相关联。一些合法的路由选择键比如“socket.usd.nyse”,"nyse.vmw","quick.orange.rabbit",你愿意用多少单词都可以,只要不超过上限的255个字节。

绑定键也必须以相同的格式。主题转发器的逻辑类似于direct类型的转发器。消息通过一个特定的路由键发送到所有与绑定键匹配的队列中。需要注意的是,关于绑定键有两种特殊的情况:*(星号)可以代替一个任意标识符 ;#(井号)可以代替零个或多个标识符。如下图:


  在上图例子中,我们发送描述动物的消息。消息会转发给包含3个单词(2个小数点)的路由键绑定的队列中。绑定键中的第一个单词描述的是速度,第二个是颜色,第三个是物种:“速度.颜色.物种”。

我们创建3个绑定:Q1绑定键是“*.orange.*”,Q2绑定键是“*.*.rabbit”,Q3绑定键是“lazy.#”。这些绑定可以概括为:Q1只对橙色的动物感兴趣。Q2则是关注兔子和所有懒的动物。

路由键为“quick.orange.rabbit”的消息会被路由到2个队列中去。而“lazy.orange.elephant”的消息同样会发往2个队列。另外“quick.orange.fox” 仅仅发往第一个队列,而"lazy.brown.fox"则只发往第二个队列。“quick.brown.fox”则所有的绑定键都不匹配而被丢弃。

如果我们违反约定,发送了只带1个或者4个标识符的选择键,像“orange”或者“quick.orange.male.rabbit”,会发生什么呢?这些消息都不匹配任何绑定,所以将被丢弃。

       另外,“lazy.orange.male.rabbit”,尽管有4个标识符,但是仍然匹配最后一个绑定键,所以会发送到第二个队列中。

       注:主题类型的转发器非常强大,可以实现其他类型的转发器。当队列绑定#绑定键,可以接受任何消息,类似于fanout转发器。当特殊字符*和#不包含在绑定键中,这个主题转发器就像一个direct类型的转发器。

完整例子:

发送端代码:

[java] view plain copy
  1. package cn.rabbitmq.topic;  
  2. import cn.rabbitmq.util.ConnectionUtil;  
  3. import com.rabbitmq.client.Channel;  
  4. import com.rabbitmq.client.Connection;  
  5. public class SendTest {  
  6.     private final static String EXCHANGE_NAME = "test_exchange_topic";  
  7.     public static void main(String[] argv) throws Exception {  
  8.         // 获取到连接以及mq通道  
  9.         Connection connection =ConnectionUtil.getConnection();  
  10.         Channel channel = connection.createChannel();  
  11.         // 声明exchange  
  12.         channel.exchangeDeclare(EXCHANGE_NAME, "topic");  
  13.         // 消息内容  
  14.         String message = "Hello World!";  
  15.         channel.basicPublish(EXCHANGE_NAME, "key.1.2"null, message.getBytes());  
  16.         System.out.println(" [x] Sent '" + message + "'");  
  17.         channel.close();  
  18.         connection.close();  
  19.     }  
  20. }  
接收端1:
[java] view plain copy
  1. package cn.rabbitmq.topic;  
  2. import cn.rabbitmq.util.ConnectionUtil;  
  3. import com.rabbitmq.client.Channel;  
  4. import com.rabbitmq.client.Connection;  
  5. import com.rabbitmq.client.QueueingConsumer;  
  6. public class RecvTest1 {  
  7.     private final static String QUEUE_NAME = "test_queue_topic_work";  
  8.     private final static String EXCHANGE_NAME = "test_exchange_topic";  
  9.     public static void main(String[] argv) throws Exception {  
  10.         // 获取到连接以及mq通道  
  11.         Connection connection = ConnectionUtil.getConnection();  
  12.         Channel channel = connection.createChannel();  
  13.         // 声明队列  
  14.         channel.queueDeclare(QUEUE_NAME, falsefalsefalsenull);  
  15.         // 绑定队列到交换机  
  16.         channel.queueBind(QUEUE_NAME, EXCHANGE_NAME, "key.*");  
  17.         // 同一时刻服务器只会发一条消息给消费者  
  18.         channel.basicQos(1);  
  19.         // 定义队列的消费者  
  20.         QueueingConsumer consumer = new QueueingConsumer(channel);  
  21.         // 监听队列,手动返回完成  
  22.         channel.basicConsume(QUEUE_NAME, false, consumer);  
  23.         // 获取消息  
  24.        while (true) {  
  25.             QueueingConsumer.Delivery delivery = consumer.nextDelivery();  
  26.             String message = new String(delivery.getBody());  
  27.             System.out.println(" [x] Received '" + message + "'");  
  28.             Thread.sleep(10);  
  29.             channel.basicAck(delivery.getEnvelope().getDeliveryTag(), false);  
  30.         }  
  31.     }  
  32. }  
接收端2:
[java] view plain copy
  1. package cn.rabbitmq.topic;  
  2. import cn.rabbitmq.util.ConnectionUtil;  
  3. import com.rabbitmq.client.Channel;  
  4. import com.rabbitmq.client.Connection;  
  5. import com.rabbitmq.client.QueueingConsumer;  
  6. public class RecvTest2 {  
  7.     private final static String QUEUE_NAME = "test_queue_topic_work2";  
  8.     private final static String EXCHANGE_NAME = "test_exchange_topic";  
  9.     public static void main(String[] argv) throws Exception {  
  10.         // 获取到连接以及mq通道  
  11.         Connection connection =ConnectionUtil.getConnection();  
  12.         Channel channel = connection.createChannel();  
  13.         // 声明队列  
  14.         channel.queueDeclare(QUEUE_NAME, falsefalsefalsenull);  
  15.         // 绑定队列到交换机  
  16.         channel.queueBind(QUEUE_NAME, EXCHANGE_NAME, "key.#");  
  17.         // 同一时刻服务器只会发一条消息给消费者  
  18.         channel.basicQos(1);  
  19.         // 定义队列的消费者  
  20.         QueueingConsumer consumer = new QueueingConsumer(channel);  
  21.         // 监听队列,手动返回完成  
  22.         channel.basicConsume(QUEUE_NAME, false, consumer);  
  23.         // 获取消息  
  24.         while (true) {  
  25.             QueueingConsumer.Delivery delivery = consumer.nextDelivery();  
  26.             String message = new String(delivery.getBody());  
  27.             System.out.println(" [x] Received '" + message + "'");  
  28.             Thread.sleep(10);  
  29.             channel.basicAck(delivery.getEnvelope().getDeliveryTag(), false);  
  30.         }  
  31.     }  
  32. }  
此时先自动生产者在启动两个消费者:可以看到消费者1接收不到消息,消费者2可以接收到消息。当把生产者的key.1.2改为key.1时可以发现两个消费者都能接收到消息。
阅读全文
0 0
原创粉丝点击