在上一个教程中,我们提高了消息传递的灵活 我们使用direct交换而不是使用仅能够进行虚拟广播的fanout交换,

并且获得了基于路由key 有选择地接收消息的可能性。

虽然使用direct 交换改进了我们的系统,但它仍然有局限性 - 它不能基于多个标准进行路由。

在我们的消息传递系统中,我们可能不仅要根据路由key订阅队列,还要根据生成消息的源来订阅队列.

为了在我们的日志记录系统中实现这种灵活性,我们需要了解更复杂的topic交换。

Topic Exchange

发送到topic 交换的消息不能具有任意 routing_key - 它必须是由点分隔的单词列表。单词可以是任何内容,但通常它们指定与消息相关的一些功能。一些有效的路由密钥示例:“ stock.usd.nyse ”,“ nyse.vmw ”,“ quick.orange.rabbit ”。路由密钥中可以包含任意数量的单词,最多可达255个字节。

绑定密钥也必须采用相同的形式。

topic 交换背后的逻辑 类似于direct 交换- 使用特定路由key发送的消息将被传递到与匹配绑定key绑定的所有队列。但是,绑定键有两个重要的特殊情况:

  • *(星号)可以替代一个单词。
  • #(hash)可以替换零个或多个单词。

在一个例子中解释这个是最容易的:

在这个例子中,我们将发送所有描述动物的消息。

消息将与包含三个单词(两个点)的路由键一起发送。路由键中的第一个单词将描述速度,第二个是颜色,第三个是物种:

<speed>.<colour>.<species>

我们创建了三个绑定

  • Q1   .orange.*
  • Q2   *.*.rabbit" and "lazy.#

这些绑定可以概括为:

  • Q1对所有orange橙色动物感兴趣。
  • Q2希望听到关于rabbit兔子的一切,以及关于lazy懒惰动物的一切。

路由密钥设置为“ quick.orange.rabbit ”的消息将传递到两个队列。

消息“ lazy.orange.elephant ”也将同时发送给他们。

另一方面,“ quick.orange.fox ”只会进入第一个队列,而“ lazy.brown.fox ”只会进入第二个队列。

“ lazy.pink.rabbit ”将仅传递到第二个队列一次,即使它匹配两个绑定。

“ quick.brown.fox ”与任何绑定都不匹配,因此它将被丢弃。

如果我们违反约定并发送带有一个或四个单词的消息,例如“ orange ”或“ quick.orange.male.rabbit”,会发生什么?好吧,这些消息将不匹配任何绑定,将丢失。

另一方面,“ lazy.orange.male.rabbit ”,即使它有四个单词,也会匹配最后一个绑定,并将被传递到第二个队列。

Topic Exchange

topic exchange 功能强大,可以像其他exchange一样。

当队列与“ # ”(哈希)绑定密钥绑定时 - 它将接收所有消息,而不管路由密钥 - 如扇出交换。

当特殊字符“ * ”(星号)和“ # ”(哈希)未在绑定中使用时,主题交换的行为就像直接交换一样

放在一起

主类

  1. import org.springframework.boot.CommandLineRunner;
  2. import org.springframework.boot.SpringApplication;
  3. import org.springframework.boot.autoconfigure.SpringBootApplication;
  4. import org.springframework.context.annotation.Bean;
  5. import org.springframework.context.annotation.Profile;
  6. import org.springframework.scheduling.annotation.EnableScheduling;
  7.  
  8. import com.xingyun.springamqp.config.RabbitAmqpTutorialsRunner;
  9.  
  10. @SpringBootApplication
  11. @EnableScheduling
  12. public class RabbitMq0x05SpringAmqpTopicSampleApplication {
  13.  
  14. public static void main(String[] args) {
  15. SpringApplication.run(RabbitMq0x05SpringAmqpTopicSampleApplication.class, args);
  16. }
  17.  
  18. @Profile("usage_message")
  19. @Bean
  20. public CommandLineRunner usage() {
  21. return new CommandLineRunner() {
  22.  
  23. @Override
  24. public void run(String... arg0) throws Exception {
  25. System.out.println("This app uses Spring Profiles to control its behavior.\n");
  26. System.out.println("Sample usage: java -jar "
  27. + "RabbitMQ_0x05_SpringAMQP_Topic_Sample-0.0.1-SNAPSHOT.jar "
  28. + "--spring.profiles.active=topics"
  29. + ",sender");
  30. }
  31. };
  32. }
  33.  
  34. @Profile("!usage_message")
  35. @Bean
  36. public CommandLineRunner tutorial() {
  37. return new RabbitAmqpTutorialsRunner();
  38. }
  39. }

Tut5Config.java

  1. import org.springframework.amqp.core.*;
  2. import org.springframework.context.annotation.Bean;
  3. import org.springframework.context.annotation.Configuration;
  4. import org.springframework.context.annotation.Profile;
  5.  
  6. import com.xingyun.springamqp.business.Tut5Receiver;
  7. import com.xingyun.springamqp.business.Tut5Sender;
  8.  
  9. @Profile({"tut5","topics"})
  10. @Configuration
  11. public class Tut5Config {
  12.  
  13. @Bean
  14. public TopicExchange topic() {
  15. return new TopicExchange("tut.topic");
  16. }
  17.  
  18. @Profile("receiver")
  19. private static class ReceiverConfig {
  20.  
  21. @Bean
  22. public Tut5Receiver receiver() {
  23. return new Tut5Receiver();
  24. }
  25.  
  26. @Bean
  27. public Queue autoDeleteQueue1() {
  28. return new AnonymousQueue();
  29. }
  30.  
  31. @Bean
  32. public Queue autoDeleteQueue2() {
  33. return new AnonymousQueue();
  34. }
  35.  
  36. @Bean
  37. public Binding binding1a(TopicExchange topic,
  38. Queue autoDeleteQueue1) {
  39. return BindingBuilder.bind(autoDeleteQueue1)
  40. .to(topic)
  41. .with("*.orange.*");
  42. }
  43.  
  44. @Bean
  45. public Binding binding1b(TopicExchange topic,
  46. Queue autoDeleteQueue1) {
  47. return BindingBuilder.bind(autoDeleteQueue1)
  48. .to(topic)
  49. .with("*.*.rabbit");
  50. }
  51.  
  52. @Bean
  53. public Binding binding2a(TopicExchange topic,
  54. Queue autoDeleteQueue2) {
  55. return BindingBuilder.bind(autoDeleteQueue2)
  56. .to(topic)
  57. .with("lazy.#");
  58. }
  59.  
  60. }
  61.  
  62. @Profile("sender")
  63. @Bean
  64. public Tut5Sender sender() {
  65. return new Tut5Sender();
  66. }
  67.  
  68. }

RabbitAmqpTutorialsRunner.java

  1. import org.springframework.beans.factory.annotation.Autowired;
  2. import org.springframework.beans.factory.annotation.Value;
  3. import org.springframework.boot.CommandLineRunner;
  4. import org.springframework.context.ConfigurableApplicationContext;
  5.  
  6. public class RabbitAmqpTutorialsRunner implements CommandLineRunner {
  7.  
  8. /**
  9. * application.properties文件中配置tutorial.client.duration=10000 需要
  10. * */
  11. @Value("${tutorial.client.duration:0}")
  12. private int duration;
  13.  
  14. @Autowired
  15. private ConfigurableApplicationContext ctx;
  16.  
  17. @Override
  18. public void run(String... args) throws Exception {
  19. // TODO Auto-generated method stub
  20. System.out.println("Ready ... running for " + duration + "ms");
  21. Thread.sleep(duration);
  22. ctx.close();
  23. }
  24.  
  25. }

Tut5Sender.java

  1. import org.springframework.amqp.core.TopicExchange;
  2. import org.springframework.amqp.rabbit.core.RabbitTemplate;
  3. import org.springframework.beans.factory.annotation.Autowired;
  4. import org.springframework.scheduling.annotation.Scheduled;
  5.  
  6. public class Tut5Sender {
  7.  
  8. @Autowired
  9. private RabbitTemplate template;
  10.  
  11. @Autowired
  12. private TopicExchange topic;
  13.  
  14. private int index;
  15.  
  16. private int count;
  17.  
  18. private final String[] keys = {"quick.orange.rabbit",
  19. "lazy.orange.elephant", "quick.orange.fox",
  20. "lazy.brown.fox", "lazy.pink.rabbit", "quick.brown.fox"};
  21.  
  22. @Scheduled(fixedDelay = 1000, initialDelay = 500)
  23. public void send() {
  24. StringBuilder builder = new StringBuilder("Hello to ");
  25. if (++this.index == keys.length) {
  26. this.index = 0;
  27. }
  28. String key = keys[this.index];
  29. builder.append(key).append(' ');
  30. builder.append(Integer.toString(++this.count));
  31. String message = builder.toString();
  32. template.convertAndSend(topic.getName(), key, message);
  33. System.out.println(" [x] Sent '" + message + "'");
  34. }
  35.  
  36. }

Tut5Receiver.java

  1. import org.springframework.amqp.rabbit.annotation.RabbitListener;
  2. import org.springframework.util.StopWatch;
  3.  
  4. public class Tut5Receiver {
  5.  
  6. @RabbitListener(queues = "#{autoDeleteQueue1.name}")
  7. public void receive1(String in) throws InterruptedException {
  8. receive(in, 1);
  9. }
  10.  
  11. @RabbitListener(queues = "#{autoDeleteQueue2.name}")
  12. public void receive2(String in) throws InterruptedException {
  13. receive(in, 2);
  14. }
  15.  
  16. public void receive(String in, int receiver) throws
  17. InterruptedException {
  18. StopWatch watch = new StopWatch();
  19. watch.start();
  20. System.out.println("instance " + receiver + " [x] Received '"
  21. + in + "'");
  22. doWork(in);
  23. watch.stop();
  24. System.out.println("instance " + receiver + " [x] Done in "
  25. + watch.getTotalTimeSeconds() + "s");
  26. }
  27.  
  28. private void doWork(String in) throws InterruptedException {
  29. for (char ch : in.toCharArray()) {
  30. if (ch == '.') {
  31. Thread.sleep(1000);
  32. }
  33. }
  34. }
  35. }

查看用法

  1. java -jar RabbitMQ_0x05_SpringAMQP_Topic_Sample-0.0.1-SNAPSHOT.jar

启动生产者

  1. java -jar RabbitMQ_0x05_SpringAMQP_Topic_Sample-0.0.1-SNAPSHOT.jar --spring.profiles.active=topics,sender

启动消费者

  1. java -jar RabbitMQ_0x05_SpringAMQP_Topic_Sample-0.0.1-SNAPSHOT.jar --spring.profiles.active=topics,receiver

译: 5. RabbitMQ Spring AMQP 之 Topic 主题的更多相关文章

  1. 译: 1. RabbitMQ Spring AMQP 之 Hello World

    本文是译文,原文请访问:http://www.rabbitmq.com/tutorials/tutorial-one-spring-amqp.html RabbitMQ 是一个Brocker (消息队 ...

  2. 译: 3. RabbitMQ Spring AMQP 之 Publish/Subscribe 发布和订阅

    在第一篇教程中,我们展示了如何使用start.spring.io来利用Spring Initializr创建一个具有RabbitMQ starter dependency的项目来创建spring-am ...

  3. 译: 2. RabbitMQ Spring AMQP 之 Work Queues

    在上一篇博文中,我们写了程序来发送和接受消息从一个队列中. 在这篇博文中我们将创建一个工作队列,用于在多个工作人员之间分配耗时的任务. Work Queues 工作队列(又称:任务队列)背后的主要思想 ...

  4. 译: 6. RabbitMQ Spring AMQP 之 RPC

    Remote procedure call (RPC) 在第二篇教程中,我们学习了如何使用工作队列在多个工作人员之间分配耗时的任务. 但是如果我们需要在远程计算机上运行一个函数并等待结果呢?嗯,这是一 ...

  5. 译: 4. RabbitMQ Spring AMQP 之 Routing 路由

    在上一个教程中,我们构建了一个简单的fanout(扇出)交换.我们能够向许多接收者广播消息. 在本教程中,我们将为其添加一个功能 - 我们将只能订阅一部分消息.例如,我们将只能将消息指向感兴趣的特定颜 ...

  6. (八)RabbitMQ消息队列-通过Topic主题模式分发消息

    原文:(八)RabbitMQ消息队列-通过Topic主题模式分发消息 前两章我们讲了RabbitMQ的direct模式和fanout模式,本章介绍topic主题模式的应用.如果对direct模式下通过 ...

  7. 译:5.RabbitMQ Java Client 之 Topics (主题)

    在 上篇博文 译:4.RabbitMQ 之Routing(路由) 中,我们改进了日志系统. 我们使用的是direct(直接交换),而不是使用只能进行虚拟广播的 fanout(扇出交换) ,并且有可能选 ...

  8. 深入剖析 RabbitMQ —— Spring 框架下实现 AMQP 高级消息队列协议

    前言 消息队列在现今数据量超大,并发量超高的系统中是十分常用的.本文将会对现时最常用到的几款消息队列框架 ActiveMQ.RabbitMQ.Kafka 进行分析对比.详细介绍 RabbitMQ 在 ...

  9. 消息中间件——RabbitMQ(九)RabbitMQ整合Spring AMQP实战!(全)

    前言 1. AMQP 核心组件 RabbitAdmin SpringAMQP声明 RabbitTemplate SimpleMessageListenerContainer MessageListen ...

随机推荐

  1. PHP 数组中取出随机取出指定数量子值集

    #关键:array_rand() 函数返回数组中的随机键名,或者如果您规定函数返回不只一个键名,则返回包含随机键名的数组.#思路:先使用array_rand()随机取出所需数量键名,然后将这些键名指向 ...

  2. 《Gradle权威指南》--Java Gradle插件

    No1: dependencies{ compile group: 'com.squareup.okhttp3',name:'okhttp',version:'3.0.1' } //缩写 depend ...

  3. 001.LVS简介及算法

    一 LVS简介 1.1 LVS介绍 LVS是linux virtual server的简写linux虚拟服务器,是一个虚拟的服务器集群系统,可以再unix/linux平台下实现负载均衡集群功能. 使用 ...

  4. 使用SQL逆向生成PDM文件

    首先导出表结构,可以使用Navicat 或者DataGrip 生成SQL文件后使用PowerDesigner 指定数据库类型,选择SQL文件即可

  5. 【Java】同步阻塞式(BIO)TCP通信

    TCP BIO 背景 网络编程的基本模型是Clien/Server模型,也就是两个进程之间进行相互通信,其中服务端提供位置信息(绑定的IP地址和监听端口),客户端通过连接操作向服务端监听的地址发起连接 ...

  6. android studio git 将项目分享到github,推送到其他平台 码云 等。

    android studio git 将项目分享到github,推送到其他平台 码云 等. 作者:韩梦飞沙 Author:han_meng_fei_sha 邮箱:313134555@qq.com E- ...

  7. 洛谷P1198 [JSOI2008]最大数(BZOJ.1012 )

    To 洛谷.1198 最大数 题目描述 现在请求你维护一个数列,要求提供以下两种操作: 1. 查询操作. 语法:Q L 功能:查询当前数列中末尾L个数中的最大的数,并输出这个数的值. 限制:L不超过当 ...

  8. Python解释数学系列——分位数Quantile

    跳转到我的博客 1. 分位数计算案例与Python代码 案例1 Ex1: Given a data = [6, 47, 49, 15, 42, 41, 7, 39, 43, 40, 36],求Q1, ...

  9. RadGridView添加序号列

    public class RowNumberColumn : GridViewDataColumn { public override System.Windows.FrameworkElement ...

  10. React系列文章:Babel编译JSX生成代码

    上次我们总结了React代码构建后的Webpack模块组织关系,今天来介绍一下Babel编译JSX生成目标代码的一些规则,并且模拟整个生成的过程. 我们还是拿最简单的代码举例: import {gre ...