在上一个教程中,咱们构建了一个简单的fanout(扇出)交换。咱们可以向许多接收者广播消息。java
在本教程中,咱们将为其添加一个功能 - 咱们将只能订阅一部分消息。例如,咱们将只能将消息指向感兴趣的特定颜色(“orange”,“black”,“green”),同时仍然可以在控制台上打印全部消息。算法
在前面的例子中,咱们已经在建立绑定。您能够在咱们的Tut3Config文件中调用这样的代码:spring
@Bean public Binding binding1(FanoutExchange fanout, Queue autoDeleteQueue1) { return BindingBuilder.bind(autoDeleteQueue1).to(fanout); }
绑定是交换和队列之间的关系。这能够简单地理解为:队列对来自此交换的消息感兴趣。app
绑定能够采用额外的routingKey参数。Spring-amqp使用流畅的API来使这种关系很是清晰。咱们将交换和队列传递到BindingBuilder,并简单地将队列绑定到交换机“与路由密钥”,以下所示:ui
@Bean public Binding binding1a(DirectExchange direct, Queue autoDeleteQueue1) { return BindingBuilder.bind(autoDeleteQueue1) .to(direct) .with("orange"); }
绑定密钥的含义取决于交换类型。咱们以前使用的 fanout 交换只是忽略了它的价值this
咱们上一个教程中的消息系统向全部消费者广播全部消息。咱们但愿扩展它以容许根据颜色类型过滤消息。例如,咱们可能须要一个程序将日志消息写入磁盘以仅接收严重错误,而不是在警告或信息日志消息上浪费磁盘空间。spa
咱们使用的是fanout exchange(扇出交换),它没有给咱们太大的灵活性 - 它只能进行无心识的广播。日志
咱们将使用direct exchange (直接交换)。direct change (直接交换) 背后的路由算法很简单 - 消息进入队列,其 绑定密钥与消息的路由密钥彻底匹配。code
为了说明这一点,请考虑如下设置:blog
在此设置中,咱们能够看到direct exchange(直接交换) X与两个绑定到它的队列。第一个队列绑定orange绑定,第二个绑定有两个绑定,一个绑定密钥为黑色,另外一个绑定为绿色。
在这样的设置中,使用路由密钥orange发布到exchange的消息 将被路由到队列Q1。路由键为black 或green 的消息将转到Q2。全部其余消息将被丢弃。
使用相同的绑定密钥绑定多个队列是彻底合法的。在咱们的例子中,咱们能够在X和Q1之间添加绑定键black的绑定。
在这种状况下,direct exchange(直接交换)将表现得像fanout (扇出)同样,并将消息广播到全部匹配的队列。路由密钥为black的消息将传送到 Q1和Q2。
咱们将此模型用于咱们的路由系统。咱们会将消息发送给direct change (直接交换),而不是fanout(扇出)。
咱们将提供颜色做为路由键。这样接收程序将可以选择它想要接收(或订阅)的颜色。让咱们首先关注发送消息。
与往常同样,咱们在Tut4Config中进行一些Spring Boot 配置:
@Bean public FanoutExchange fanout() { return new FanoutExchange("tut.fanout"); }
咱们已经准备好发送消息了。颜色,如图中所示,能够是“orange”,“black”或“green”之一。
接收消息将像上一个教程同样工做,但有一个例外 - 咱们将为咱们感兴趣的每种颜色建立一个新的绑定。这也适用于Tut4Config
@Bean public DirectExchange direct() { return new DirectExchange("tut.direct"); } ... @Bean public Binding binding1a(DirectExchange direct, Queue autoDeleteQueue1) { return BindingBuilder.bind(autoDeleteQueue1) .to(direct) .with("orange"); }
配置类
Tut4Config.java
import org.springframework.amqp.core.*; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Profile; import com.xingyun.springamqp.business.Tut4Receiver; import com.xingyun.springamqp.business.Tut4Sender; @Profile({"tut4","routing"}) @Configuration public class Tut4Config { @Bean public DirectExchange direct() { return new DirectExchange("tut.direct"); } @Profile("receiver") private static class ReceiverConfig { @Bean public Queue autoDeleteQueue1() { return new AnonymousQueue(); } @Bean public Queue autoDeleteQueue2() { return new AnonymousQueue(); } @Bean public Binding binding1a(DirectExchange direct, Queue autoDeleteQueue1) { return BindingBuilder.bind(autoDeleteQueue1) .to(direct) .with("orange"); } @Bean public Binding binding1b(DirectExchange direct, Queue autoDeleteQueue1) { return BindingBuilder.bind(autoDeleteQueue1) .to(direct) .with("black"); } @Bean public Binding binding2a(DirectExchange direct, Queue autoDeleteQueue2) { return BindingBuilder.bind(autoDeleteQueue2) .to(direct) .with("green"); } @Bean public Binding binding2b(DirectExchange direct, Queue autoDeleteQueue2) { return BindingBuilder.bind(autoDeleteQueue2) .to(direct) .with("black"); } @Bean public Tut4Receiver receiver() { return new Tut4Receiver(); } } @Profile("sender") @Bean public Tut4Sender sender() { return new Tut4Sender(); } }
生产者
Tut4Sender.java
import org.springframework.amqp.core.DirectExchange; import org.springframework.amqp.rabbit.core.RabbitTemplate; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.scheduling.annotation.Scheduled; public class Tut4Sender { @Autowired private RabbitTemplate template; @Autowired private DirectExchange direct; private int index; private int count; private final String[] keys = {"orange", "black", "green"}; @Scheduled(fixedDelay = 1000, initialDelay = 500) public void send() { StringBuilder builder = new StringBuilder("Hello to "); if (++this.index == 3) { this.index = 0; } String key = keys[this.index]; builder.append(key).append(' '); builder.append(Integer.toString(++this.count)); String message = builder.toString(); template.convertAndSend(direct.getName(), key, message); System.out.println(" [x] Sent '" + message + "'"); } }
消费者
Tut4Receiver.java
import org.springframework.amqp.rabbit.annotation.RabbitListener; import org.springframework.util.StopWatch; public class Tut4Receiver { @RabbitListener(queues = "#{autoDeleteQueue1.name}") public void receive1(String in) throws InterruptedException { receive(in, 1); } @RabbitListener(queues = "#{autoDeleteQueue2.name}") public void receive2(String in) throws InterruptedException { receive(in, 2); } public void receive(String in, int receiver) throws InterruptedException { StopWatch watch = new StopWatch(); watch.start(); System.out.println("instance " + receiver + " [x] Received '" + in + "'"); doWork(in); watch.stop(); System.out.println("instance " + receiver + " [x] Done in " + watch.getTotalTimeSeconds() + "s"); } private void doWork(String in) throws InterruptedException { for (char ch : in.toCharArray()) { if (ch == '.') { Thread.sleep(1000); } } } }
查看用法
java -jar RabbitMQ_0x04_SpringAMQP_Routing_Sample-0.0.1-SNAPSHOT.jar
启动生产者
java -jar RabbitMQ_0x04_SpringAMQP_Routing_Sample-0.0.1-SNAPSHOT.jar --spring.profiles.active=routing,sender
启动消费者
java -jar RabbitMQ_0x04_SpringAMQP_Routing_Sample-0.0.1-SNAPSHOT.jar --spring.profiles.active=routing,receiver