Spring Boot RabbitMQ 入门(四)之 Topi
2017-02-16 本文已影响781人
5d44bc28b93d
0.回顾
Spring Boot RabbitMQ 入门(三)之 Fanout交换器
上篇文章我们学习了以下几点:
- 1.如何创建消息生产者
- 2.如何使用消息生产者发送消息
- 3.如何定义Fanout交换器
- 4.将对列绑定到交换器从而测试其特性
1.Topic交换器介绍
Topic.png
如上图所示
此类交换器使得来自不同的源头的消息可以到达一个对列,其实说的更明白一点就是模糊匹配的意思,例如:上图中红色对列的routekey为usa.#,#代表匹配任意字符,但是要想消息能到达此对列,usa.必须匹配后面的#好可以随意。图中usa.news usa.weather,都能找到红色队列,符号“#”匹配一个或多个词,符号“”匹配不多不少一个词。因此“usa.#”能够匹配到“usa.news.XXX”,但是“usa.” 只会匹配到“usa.XXX”。
注:
交换器说到底是一个名称与队列绑定的列表。当消息发布到交换器时,实际上是由你所连接的信道,将消息路由键同交换器上绑定的列表进行比较,最后路由消息
2.Topic交换器实践
2.1创建交换器
@Bean
public TopicExchange topicExchange() {
return new TopicExchange(EXCHANGE);
}
2.2创建队并
@Bean
public Queue queue() {
return new Queue("spring-queue", true); //队列持久
}
@Bean
public Queue queue2() {
return new Queue("spring-queue2", true); //队列持久
}
2.3对列绑定并关联到ROUTINGKEY
此处要理解Topic交换器介绍中的注部分就明白
两个对列分别匹配两个不同规则
public static final String EXCHANGE = "spring-topic-exchange";
public static final String ROUTINGKEY1 = "weather-routingKey.*";
public static final String ROUTINGKEY2 = "msg-routingKey.#";
@Bean
public Binding binding() {
return BindingBuilder.bind(queue()).to(topicExchange()).with(ROUTINGKEY1);
}
@Bean
public Binding binding2() {
return BindingBuilder.bind(queue2()).to(topicExchange()).with(ROUTINGKEY2);
}
2.4创建消费者,分别消费两对列
Bean
public SimpleMessageListenerContainer messageContainer() {
SimpleMessageListenerContainer container = new SimpleMessageListenerContainer(connectionFactory());
container.setQueues(queue());
container.setExposeListenerChannel(true);
container.setMaxConcurrentConsumers(1);
container.setConcurrentConsumers(1);
container.setAcknowledgeMode(AcknowledgeMode.MANUAL); //设置确认模式手工确认
container.setMessageListener(new ChannelAwareMessageListener() {
@Override
public void onMessage(Message message, Channel channel) throws Exception {
byte[] body = message.getBody();
System.out.println("receive msg queue: " + new String(body));
Thread.sleep(10000);
channel.basicAck(message.getMessageProperties().getDeliveryTag(), false); //确认消息成功消费
}
});
return container;
}
@Bean
public SimpleMessageListenerContainer messageContainer2() {
SimpleMessageListenerContainer container = new SimpleMessageListenerContainer(connectionFactory());
container.setQueues(queue2());
container.setExposeListenerChannel(true);
container.setMaxConcurrentConsumers(1);
container.setConcurrentConsumers(1);
container.setAcknowledgeMode(AcknowledgeMode.MANUAL); //设置确认模式手工确认
container.setMessageListener(new ChannelAwareMessageListener() {
@Override
public void onMessage(Message message, Channel channel) throws Exception {
byte[] body = message.getBody();
System.out.println("receive msg queue2: " + new String(body));
Thread.sleep(10000);
channel.basicAck(message.getMessageProperties().getDeliveryTag(), false); //确认消息成功消费
}
});
return container;
}
2.5消息生产者生产消息
@Autowired
RabbitTemplate template;
public void send(String context) {
template.convertAndSend(RabbitConfig.EXCHANGE, "weather-routingKey.a", context);
}
2.验证
此处为了方便验证就不采用发送者发送了,直接用RabbitMQ管理端进行发送
- 1情况一
我们匹配对列2的msg-routingKey.#
输出结果如下
预计情况会queue2对列消费者消费消息
receive msg queue2: 21213
- 2情况二
我们前文讲到采用#可以匹配多个字符
我们使用routingKey =msg-routingKey.a.b如果前文正确,则
输出结果如下
receive msg queue2: msg-routingKey.a.b
- 3.情况三
*匹配只能是单个字符所以我们我们使用routingKey =weather-routingKey.a如果前文正确,则输出对列queue接受到消息
结果如下:
receive msg queue: weather-routingKey.a
- 4.情况四
我们模拟*匹配“多个字符”的情况routingKey =weather-routingKey.a.b
如果前文正确,则消息会进入消息"黑洞",被丢弃,没有输出。
结果如下:
.
最后
注:此处的多个字符是指以"."间隔为一个。
Direct其实就是要求routingKey 完全匹配,所以就不再赘述