RabbitMQ工作模式(5) - 主题模式

概念

主题模式(Topic Exchange)是 RabbitMQ 中一种灵活且强大的消息传递模式,它允许生产者根据消息的特定属性将消息发送到一个交换机,并且消费者可以根据自己的需求来接收感兴趣的消息。主题交换机根据消息的路由键和绑定队列的路由键进行模糊匹配,支持通配符 *#,从而实现了更灵活的消息路由和分发。

工作流程

  1. 生产者发送消息: 生产者将消息发送到一个主题交换机,并指定一个特定的路由键。

  2. 交换机根据路由键路由消息 : 主题交换机根据消息的路由键和绑定队列的路由键进行模糊匹配。路由键可以包含多个单词,以 . 分隔,例如 stock.usd.nyseweather.usa.ca.sunny 等。

  3. 消息发送到匹配的队列 : 如果消息的路由键与绑定队列的路由键完全匹配,则将消息发送到对应的队列中。如果路由键中包含通配符 *#,则可以匹配多个单词或多个级别的单词,从而实现更灵活的匹配规则。

  4. 消费者接收消息 : 消费者可以根据自己的需求来选择监听匹配的队列,从而接收感兴趣的消息。消费者可以使用通配符 * 匹配一个单词,或使用 # 匹配零个或多个单词。

发送到类型是 topic 交换机的消息的 routing_key 不能随意写,必须满足一定的要求,它必须是一个单词列表,以点号分隔开

优点

  • 灵活性:生产者可以根据消息的特定属性来发送消息,消费者可以根据自己的需求来接收感兴趣的消息。
  • 精确匹配:支持精确的路由键匹配和模糊匹配,可以根据实际需求定义复杂的路由规则。
  • 扩展性:可以根据需要动态地添加和修改绑定规则,而不需要停止消息传递服务。

主题模式适用于需要根据消息的特定属性进行灵活路由和分发的场景,例如事件处理、消息过滤、数据分析等。

Springboot集成

示例: 系统应用程序测试的时候,会有不同的BUG,测试人员会将不同的BUG按照规范打上标签(相当于routingKey),然后发送到mq中,然后通过主题模式分发;

标签内容:bug归属.模块.等级 例如: back.order.severity

分发规则如下:

第一个消费者是前端的开发人员:处理所有严重的前端BUG:front.#

第二个消费者是后端负责订单模块开发人员:处理所有的后端order模块BUG:back.order.*

另外还有多个消费者处理不同的BUG,这里只用两个做示例

1.创建队列和交换机并绑定

在TopicConfig中配置

java 复制代码
package com.model.config;

import org.springframework.amqp.core.*;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

/**
 * @Author: Haiven
 * @Time: 2024/4/22 11:55
 * @Description: TODO
 */
@Configuration
public class TopicConfig {

    /**
     * 主题模式交换机
     * @return exchange
     */
    @Bean(name = "topicExchange")
    public Exchange getTopicExchange(){
        return ExchangeBuilder
                .topicExchange("exchange_topic")
                .build();
    }

    /**
     * 主题队列 01
     * @return queue
     */
    @Bean(name = "topicQueue01")
    public Queue getTopicQueue01(){
        return QueueBuilder
                .durable("queue_topic_01")
                .build();
    }

    /**
     * 主题队列 02
     * @return queue
     */
    @Bean(name = "topicQueue02")
    public Queue getTopicQueue02(){
        return QueueBuilder
                .durable("queue_topic_02")
                .build();
    }

    /**
     * 绑定队列 01
     * @return binding
     */
    @Bean
    public Binding getTopicBinding01(){
        return BindingBuilder
                .bind(getTopicQueue01())
                .to(getTopicExchange())
                //路由键 队列1接收debug级别的消息
                .with("front.#")
                .noargs();
    }

    /**
     * 绑定队列 02
     * @return binding
     */
    @Bean
    public Binding getTopicBinding02(){
        return BindingBuilder
                .bind(getTopicQueue02())
                .to(getTopicExchange())
                // 路由键 队列2接收info级别的消息
                .with("back.order.*")
                .noargs();
    }
}

主题模式的交换机类型为TopicExchange

2.创建消费者

TopicConsumer

java 复制代码
package com.model.listener;

import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Component;

/**
 * @Author: Haiven
 * @Time: 2024/4/22 10:08
 * @Description: TODO
 */
@Component
public class TopicConsumer {

    @RabbitListener(queues = {"queue_topic_01"})
    public void topicConsumer01(String msg){
        System.out.println("消费者 -01- 接收消息:" + msg);
    }

    @RabbitListener(queues = {"queue_topic_02"})
    public void topicConsumer02(String msg){
        System.out.println("消费者 -02- 接收消息:" + msg);
    }
}

3.创建生产者并发送消息

java 复制代码
package com.model.controller;

import com.code.domain.Response;
import com.model.service.RabbitService;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.Resource;


/**
 * @Author: Haiven
 * @Time: 2024/4/19 9:46
 * @Description: TODO
 */
@RestController
@RequestMapping("/producer")
public class ProducerController {

    @Resource
    private RabbitService rabbitService;

    @GetMapping("/simple")
    public Response<Void> simple(String msg){
        boolean res = rabbitService.simple(msg);
        return res ? Response.success() : Response.fail();
    }

    @GetMapping("/work")
    public Response<Void> work(String msg){
        boolean res = rabbitService.work(msg);
        return res ? Response.success() : Response.fail();
    }

    @GetMapping("/sub")
    public Response<Void> sub(String msg){
        boolean res = rabbitService.sub(msg);
        return res ? Response.success() : Response.fail();
    }

    @GetMapping("/routing")
    public Response<Void> routing(String msg, String type){
        boolean res = rabbitService.routing(msg, type);
        return res ? Response.success() : Response.fail();
    }

    @GetMapping("/topic")
    public Response<Void> topic(String msg, String type){
        boolean res = rabbitService.topic(msg, type);
        return res ? Response.success() : Response.fail();
    }
}
java 复制代码
package com.model.service.impl;

import com.model.service.RabbitService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;

/**
 * @Author: Haiven
 * @Time: 2024/4/19 10:51
 * @Description: TODO
 */
@Service
@Slf4j
public class RabbitServiceImpl implements RabbitService {

    @Resource
    private RabbitTemplate rabbitTemplate;

    @Value("${rabbitmq.simple.queue}")
    private String simpleQueue;

    @Value("${rabbitmq.work.queue}")
    private String workQueue;

    @Override
    public boolean simple(String msg) {
        try {
            rabbitTemplate.convertAndSend(simpleQueue, msg);
            return true;
        }catch (Exception e){
            e.printStackTrace();
            return false;
        }
    }

    @Override
    public boolean work(String msg) {
        try {
            rabbitTemplate.convertAndSend(workQueue, msg);
            return true;
        }catch (Exception e){
            e.printStackTrace();
            return false;
        }
    }

    @Override
    public boolean sub(String msg) {
        try {
            //路由模式就不能直接发送消息到队列了, 而是发送到交换机,由交换机进行广播, routingKey为路由Key 订阅模式给""
            rabbitTemplate.convertAndSend("exchange_sub","", msg);
            return true;
        }catch (Exception e){
            e.printStackTrace();
            return false;
        }
    }

    @Override
    public boolean routing(String msg, String type) {
        System.out.println("理由模式发送消息:msg="+msg+",type="+type+"");
        try {
            //路由模式就不能直接发送消息到队列了, 而是发送到交换机,由交换机进行广播, routingKey为路由Key 订阅模式给""
            rabbitTemplate.convertAndSend("exchange_routing",type, msg);
            return true;
        }catch (Exception e){
            e.printStackTrace();
            return false;
        }
    }

    @Override
    public boolean topic(String msg, String type) {
        System.out.println("主题模式发送消息:msg="+msg+",type="+type+"");
        try {
            //主题模式会根据 type的通配符进行分发
            rabbitTemplate.convertAndSend("exchange_topic",type, msg);
            return true;
        }catch (Exception e){
            e.printStackTrace();
            return false;
        }
    }
}

4.发送消息

接口调用发送消息, type字段为消息的级别

后台接收

相关推荐
小江的记录本1 小时前
【事务】Spring Framework核心——事务管理:ACID特性、隔离级别、传播行为、@Transactional底层原理、失效场景
java·数据库·分布式·后端·sql·spring·面试
半桶水专家5 小时前
Kafka 性能瓶颈 → JMX 指标对照表
分布式·kafka
殷紫川6 小时前
别再乱用了!幂等处理与分布式锁,90% 开发者都踩过的坑与正确落地姿势
分布式·架构
Jack_David9 小时前
Kafka批量消息发送
java·分布式·kafka
wanhengidc10 小时前
服务器托管对企业的作用
大数据·运维·服务器·分布式·智能手机
Code知行合壹10 小时前
Spark使用总结
大数据·分布式·spark
Swift社区10 小时前
分布式能力不是功能,而是一种架构约束
分布式·架构
0xDevNull11 小时前
Apache Kafka 完全指南
分布式·kafka
zb2006412012 小时前
RabbitMQ 客户端 连接、发送、接收处理消息
分布式·rabbitmq·ruby
夜空下的星12 小时前
Springboot结合RabbitMQ实现延时队列
spring boot·rabbitmq·java-rabbitmq