rabbitmq基础(3)主题交换机 java代码
回顾一下主题交换机概念
Topic Exchange
主题交换机,这个交换机其实跟直连交换机流程差不多,但是它的特点就是在它的路由键和绑定键之间是有规则的。
简单地介绍下规则:
*(星号) 用来表示一个单词 (必须出现的)
#(井号) 用来表示任意数量(零个或多个)单词
通配的绑定键是跟队列进行绑定的,举个小例子
队列Q1 绑定键为 .TT. 队列Q2绑定键为 TT.#
如果一条消息携带的路由键为 A.TT.B,那么队列Q1将会收到;
如果一条消息携带的路由键为TT.AA.BB,那么队列Q2将会收到;
主题交换机是非常强大的,为啥这么膨胀?
当一个队列的绑定键为 “#”(井号) 的时候,这个队列将会无视消息的路由键,接收所有的消息。当 * (星号) 和 # (井号) 这两个特殊字符都未在绑定键中出现的时候,此时主题交换机就拥有的直连交换机的行为。
所以主题交换机也就实现了扇形交换机的功能,和直连交换机的功能。
上代码:
(1)主题交换机配置类
package com.zyw.rabbitmq.config;
import org.springframework.amqp.core.Binding;
import org.springframework.amqp.core.BindingBuilder;
import org.springframework.amqp.core.Queue;
import org.springframework.amqp.core.TopicExchange;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* @author zyw
* 主题交换机
* 主题交换机,这个交换机其实跟直连交换机流程差不多,
* 但是它的特点就是在它的路由键和绑定键之间是有规则的。
*/
@Configuration
public class TopicRabbitConfig {
/**
* 绑定键
*/
public final static String man = "topic.man";
public final static String woman = "topic.woman";
@Bean
public Queue firstQueue() { //队列 起名
return new Queue(TopicRabbitConfig.man);
}
@Bean
public Queue secondQueue() {//队列 起名
return new Queue(TopicRabbitConfig.woman);
}
@Bean
TopicExchange exchange() {
return new TopicExchange("topicExchange");
}
/**
* 将firstQueue和topicExchange绑定,而且绑定的键值为topic.man
这样只要是消息携带的路由键是topic.man,才会分发到该队列
* @return
*/
@Bean
Binding bindingExchangeMessage() {
return BindingBuilder.bind(firstQueue()).to(exchange()).with(man);
}
/**
* 将secondQueue和topicExchange绑定,而且绑定的键值为用上通配路由键规则topic.#
* 这样只要是消息携带的路由键是以topic.开头,都会分发到该队列
* 适用场景:消息需要基于多重条件进行路由到达对应队列,
* 例如:日志系统,不仅可以根据日志的级别而且能根据日志的来源进行订阅。
* @return
*/
@Bean
Binding bindingExchangeMessage2() {
return BindingBuilder.bind(secondQueue()).to(exchange()).with("topic.#");
}
}
(2)主题交换机生成者
package com.zyw.rabbitmq.controller;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.HashMap;
import java.util.Map;
/**
* @author zyw
* 主题交换机
*/
@EnableScheduling
@Configuration
public class TopicController {
@Autowired
RabbitTemplate rabbitTemplate;
@Scheduled(cron = "0 */1 * * * ?")
public void sendTopicMessage(){ // 主题交换机
System.out.println("---------主题交换机開始----------------------");
Map<String,Object> map = new HashMap<>();
map.put("id","1111");
map.put("name","zyw");
//交换机---路由键--值
rabbitTemplate.convertAndSend("topicExchange", "topic.man", map);
System.out.println("---------主题交换机結束----------------------");
}
}
(3)消费者
下面这个可以正常接收到topic.man,和topic.*的消息
package com.zyw.rabbitcustomer;
import org.springframework.amqp.rabbit.annotation.RabbitHandler;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Component;
import java.util.Map;
/**
* @author zyw
*/
@Component
@RabbitListener(queues = "topic.man")
public class TopicManReceiver {
@RabbitHandler
public void process(Map<String,Object> map){
System.out.println("TopicManReceiver消费者收到消息 : " + map.toString());
}
}
下面这个可以正常接收到topic.woman,和topic.*的消息
package com.zyw.rabbitcustomer;
import org.springframework.amqp.rabbit.annotation.RabbitHandler;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Component;
import java.util.Map;
/**
* @author zyw
*/
@Component
@RabbitListener(queues = "topic.woman")
public class TopicReceiver { // 只有绑定路由键是topic.woman或者topic.* 才能监听到队列
@RabbitHandler
public void process(Map<String,Object> map){
System.out.println("TopicReceiver消费者收到消息33 : " + map.toString());
}
}
消费者返回消息
DirectReceiver消费者收到消息 : 66666
TopicManReceiver消费者收到消息 : {name=zyw, id=1111}
TopicReceiver消费者收到消息33 : {name=zyw, id=1111}
特别注意 虽然我们在生成者只绑定了topic.man这个但是实际上topic.woman这个也可正常接收到消息,应为我们在配置类中将路由topic.*已经和交换机绑定了。