SpringBoot整合RabbitMQ之Topic主题交换器
RabbitMQ中的Topic主题交换器:
Topic交换器是主题模式,通过模式匹配分发消息的路由键属性,将路由键和某种模式进行匹配,此时队列需要绑定一种模式,Topic交换器将路由键和绑定的字符串切分成单词,这些单词直接用点“.”隔开。该交换器会识别两个通配符:“#”和“*”,其中“#”匹配0个或多个单词,“*”匹配不多不少一个单词。
以下案例为实现Topic主题交换器的过程,本案例在上一章的基础之上编写的,需要这两个项目:rabbitmq-provider (生产者),一个rabbitmq-consumer(消费者)。
首先在rabbitmq-provider项目上创建 TopicRabbitConfig配置类
package com.rabbitmq.provider.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; @Configuration public class TopicRabbitConfig { // 绑定键 private final String man = "topic.man"; private final String woman = "topic.women"; @Bean Queue firstQueue() { return new Queue(man); } @Bean Queue secondQueue() { return new Queue(woman); } @Bean TopicExchange exchange(){ return new TopicExchange("topicExchange"); } //将firstQueue和topicExchange绑定,而且绑定的键值为topic.man //这样只要是消息携带的路由键是topic.man,才会分发到该队列 @Bean Binding bindingExchangeMessage(){ return BindingBuilder.bind(firstQueue()).to(exchange()).with(man); } //将secondQueue和topicExchange绑定,而且绑定的键值为用上通配路由键规则topic.# // 这样只要是消息携带的路由键是以topic.开头,都会分发到该队列 @Bean Binding bindingExchangeMessage2(){ return BindingBuilder.bind(secondQueue()).to(exchange()).with("topic.#"); } }
然后在Controller里面多加两个接口
@GetMapping("/sendTopicMessage1") public String sendTopicMessage1() { String messageId = String.valueOf(UUID.randomUUID()); String messageData = "message: M A N "; String createTime = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")); Map<String, Object> manMap = new HashMap<>(); manMap.put("messageId", messageId); manMap.put("messageData", messageData); manMap.put("createTime", createTime); rabbitTemplate.convertAndSend("topicExchange", "topic.man", manMap); return "ok"; } @GetMapping("/sendTopicMessage2") public String sendTopicMessage2() { String messageId = String.valueOf(UUID.randomUUID()); String messageData = "message: woman is all "; String createTime = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")); Map<String, Object> womanMap = new HashMap<>(); womanMap.put("messageId", messageId); womanMap.put("messageData", messageData); womanMap.put("createTime", createTime); rabbitTemplate.convertAndSend("topicExchange", "topic.woman", womanMap); return "ok"; }
生产者这边的操作已经完成,接下来去rabbitmq-consumer项目上编写后续代码
创建TopicManReceiver
package com.rabbitmq.consumer.receiver; import org.springframework.amqp.rabbit.annotation.RabbitHandler; import org.springframework.amqp.rabbit.annotation.RabbitListener; import org.springframework.stereotype.Component; import java.util.Map; @Component @RabbitListener(queues = "topic.man") public class TopicManReceiver { @RabbitHandler public void process(Map message){ System.out.println("TopicManReceiver消费者收到消息 = " + message.toString()); } }
创建TopicWoManReceiver
package com.rabbitmq.consumer.receiver; import org.springframework.amqp.rabbit.annotation.RabbitHandler; import org.springframework.amqp.rabbit.annotation.RabbitListener; import org.springframework.stereotype.Component; import java.util.Map; @Component @RabbitListener(queues = "topic.woman") public class TopicWoManReceiver { @RabbitHandler public void process(Map message) { System.out.println("TopicWoManReceiver消费者收到消息 = " + message); } }
创建TopicRabbitConfig配置类
package com.rabbitmq.consumer.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; @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,才会分发到该队列 @Bean Binding bindingExchangeMessage() { return BindingBuilder.bind(firstQueue()).to(exchange()).with(man); } //将secondQueue和topicExchange绑定,而且绑定的键值为用上通配路由键规则topic.# // 这样只要是消息携带的路由键是以topic.开头,都会分发到该队列 @Bean Binding bindingExchangeMessage2() { return BindingBuilder.bind(secondQueue()).to(exchange()).with("topic.#"); } }
然后把这两个项目跑起来,使用postman工具调用/sendTopicMessage1接口
再调用/sendTopicMessage2接口
可以看到,sendTopicMessage1调用的时候
man和woman都消费到了信息,因为它们使用的是主题交换机,而woman绑定的路由是topic.#,“#”匹配0个或多个单词,所以woman能消费到这个接口的信息
当调用sendTopicMessage2的时候,
man消费不到woman的信息,因为man的路由是topic.man,只能消费topic.man的信息。