【RabbitMQ——SpringBoot整合】

news/2024/9/29 14:20:31 标签: java-rabbitmq, rabbitmq, spring boot

1. fanout模式

Fanout 交换器(Exchange)是 RabbitMQ 中的一种消息路由模式。它是一种广播式的交换器,会将接收到的消息发送给所有绑定到该交换器的队列,而不考虑路由键(routing key)。这意味着无论消息发布时指定了什么路由键,Fanout 交换器都会忽略这些信息,并简单地将消息复制并分发给所有的绑定队列。

1.1 配置类

@Configuration
public class FanoutRabbitConfig {

    // 1. 声明注册fanout模式的交换机
    @Bean
    public FanoutExchange fanoutOrderExchange() {
        //  return new DirectExchange("TestDirectExchange",true,true);
        return new FanoutExchange("fanout_order_exchange", true, false);
    }
    // 2. 申明队列sms.fanout.queue  email.fanout.queue duanxin.fanout.queue
    @Bean
    public Queue fanoutEmailQueue() {
        // durable:是否持久化,默认是false,持久化队列:会被存储在磁盘上,当消息代理重启时仍然存在,暂存队列:当前连接有效
        // exclusive:默认也是false,只能被当前创建的连接使用,而且当连接关闭后队列即被删除。此参考优先级高于durable
        // autoDelete:是否自动删除,当没有生产者或者消费者使用此队列,该队列会自动删除。
        //   return new Queue("TestDirectQueue",true,true,false);
        //一般设置一下队列的持久化就好,其余两个就是默认false
        return new Queue("email.fanout.queue", true);
    }
    @Bean
    public Queue fanoutSmsQueue() {
        return new Queue("sms.fanout.queue", true);
    }
    @Bean
    public Queue fanoutWeixinQueue() {
        return new Queue("weixin.fanout.queue", true);
    }
    // 3. 完成绑定关系
    @Bean
    public Binding fanoutBindingDirect1() {
        return BindingBuilder.bind(fanoutEmailQueue()).to(fanoutOrderExchange());
    }
    @Bean
    public Binding fanoutBindingDirect2() {
        return BindingBuilder.bind(fanoutSmsQueue()).to(fanoutOrderExchange());
    }
    @Bean
    public Binding fanoutBindingDirect3() {
        return BindingBuilder.bind(fanoutWeixinQueue()).to(fanoutOrderExchange());
    }

}

1.2 生产者

public void makeOrder(Long userId, Long productId, int num) {
    // 1: 模拟用户下单
    String orderNumer = UUID.randomUUID().toString();
    // 2: 根据商品id productId 去查询商品的库存
    // int numstore = productSerivce.getProductNum(productId);
    // 3:判断库存是否充足
    // if(num >  numstore ){ return  "商品库存不足..."; }
    // 4: 下单逻辑
    // orderService.saveOrder(order);
    // 5: 下单成功要扣减库存
    // 6: 下单完成以后
    System.out.println("用户 " + userId + ",订单编号是:" + orderNumer);
    // 发送订单信息给RabbitMQ fanout
    String exchangeName = "fanout_order_exchange";
    String routeKey = "";
    rabbitTemplate.convertAndSend(exchangeName, routeKey, orderNumer);
}

1.3 消费者

// bindings其实就是用来确定队列和交换机绑定关系
@RabbitListener(queues = {"email.fanout.queue"})
@Component
public class FanoutEmailService {
    // @RabbitHandler 代表此方法是一个消息接收的方法。该不要有返回值
    @RabbitHandler
    public void messagerevice(String message){
        // 此处省略发邮件的逻辑
        System.out.println("fanout-email-------------->" + message);
    }
}
// bindings其实就是用来确定队列和交换机绑定关系
@RabbitListener(queues = {"sms.fanout.queue"})
@Component
public class FanoutSMSService {
    // @RabbitHandler 代表此方法是一个消息接收的方法。该不要有返回值
    @RabbitHandler
    public void messagerevice(String message){
        // 此处省略发邮件的逻辑
        System.out.println("fanout-sms-------------->" + message);
    }
}
@RabbitListener(queues = {"weixin.fanout.queue"})
@Component
public class FanoutWeixinService {

    // @RabbitHandler 代表此方法是一个消息接收的方法。该不要有返回值
    @RabbitHandler
    public void messagerevice(String message){
        // 此处省略发邮件的逻辑
        System.out.println("fanout-weixin-------------->" + message);
    }
}

2. direct模式

Direct 交换器根据消息的路由键(routing key)和队列绑定时指定的路由键进行精确匹配来决定消息的分发。如果一个队列绑定了带有特定路由键的 Direct 交换器,那么只有当发布到该交换器的消息携带相同的路由键时,消息才会被发送到这个队列。

2.1 配置类

注意配置类中声明的交换机的类型,以及队列携带的路由key

@Configuration
public class DirectRabbitConfig {

    // 1. 声明注册fanout模式的交换机
    @Bean
    public DirectExchange directOrderExchange() {
        return new DirectExchange("direct_order_exchange", true, false);
    }
    // 2. 申明队列sms.fanout.queue  email.fanout.queue duanxin.fanout.queue
    @Bean
    public Queue directEmailQueue() {
        // durable:是否持久化,默认是false,持久化队列:会被存储在磁盘上,当消息代理重启时仍然存在,暂存队列:当前连接有效
        // exclusive:默认也是false,只能被当前创建的连接使用,而且当连接关闭后队列即被删除。此参考优先级高于durable
        // autoDelete:是否自动删除,当没有生产者或者消费者使用此队列,该队列会自动删除。
        //   return new Queue("TestDirectQueue",true,true,false);
        //一般设置一下队列的持久化就好,其余两个就是默认false
        return new Queue("email.direct.queue", true);
    }
    @Bean
    public Queue directSmsQueue() {
        return new Queue("sms.direct.queue", true);
    }
    @Bean
    public Queue directWeixinQueue() {
        return new Queue("weixin.direct.queue", true);
    }
    // 3. 完成绑定关系
    @Bean
    public Binding directBindingDirect1() {
        return BindingBuilder.bind(directWeixinQueue()).to(directOrderExchange()).with("weixin");
    }
    @Bean
    public Binding directBindingDirect2() {
        return BindingBuilder.bind(directSmsQueue()).to(directOrderExchange()).with("sms");
    }
    @Bean
    public Binding directBindingDirect3() {
        return BindingBuilder.bind(directEmailQueue()).to(directOrderExchange()).with("email");
    }

}

2.2 生产者

    public void makeOrderDirect(Long userId, Long productId, int num) {
        // 1: 模拟用户下单
        String orderNumer = UUID.randomUUID().toString();
        // 2: 根据商品id productId 去查询商品的库存
        // int numstore = productSerivce.getProductNum(productId);
        // 3:判断库存是否充足
        // if(num >  numstore ){ return  "商品库存不足..."; }
        // 4: 下单逻辑
        // orderService.saveOrder(order);
        // 5: 下单成功要扣减库存
        // 6: 下单完成以后
        System.out.println("用户 " + userId + ",订单编号是:" + orderNumer);
        String exchangeName = "direct_order_exchange";
        rabbitTemplate.convertAndSend(exchangeName, "email", orderNumer);
        rabbitTemplate.convertAndSend(exchangeName, "weixin", orderNumer);
    }

2.3 消费者

// bindings其实就是用来确定队列和交换机绑定关系
@RabbitListener(queues = {"email.direct.queue"})
@Component
public class DirectEmailService {
    // @RabbitHandler 代表此方法是一个消息接收的方法。该不要有返回值
    @RabbitHandler
    public void messagerevice(String message){
        // 此处省略发邮件的逻辑
        System.out.println("direct-email-------------->" + message);
    }
}
// bindings其实就是用来确定队列和交换机绑定关系
@RabbitListener(queues = {"sms.direct.queue"})
@Component
public class DirectSMSService {
    // @RabbitHandler 代表此方法是一个消息接收的方法。该不要有返回值
    @RabbitHandler
    public void messagerevice(String message){
        // 此处省略发邮件的逻辑
        System.out.println("direct-sms-------------->" + message);
    }
}
@RabbitListener(queues = {"weixin.direct.queue"})
@Component
public class DirectWeixinService {

    // @RabbitHandler 代表此方法是一个消息接收的方法。该不要有返回值
    @RabbitHandler
    public void messagerevice(String message){
        // 此处省略发邮件的逻辑
        System.out.println("direct-weixin-------------->" + message);
    }
}

3. topic模式

Topic 交换器是 RabbitMQ 中用于更灵活的消息路由模式。它结合了 Direct 交换器的基于路由键匹配的特点,但允许使用通配符进行部分匹配。这使得 Topic 交换器非常适合于实现动态且复杂的路由逻辑。

3.1 配置类

无,采用注解的方式

3.2 生产者

    public void makeOrderTopic(Long userId, Long productId, int num) {
        // 1: 模拟用户下单
        String orderNumer = UUID.randomUUID().toString();
        // 2: 根据商品id productId 去查询商品的库存
        // int numstore = productSerivce.getProductNum(productId);
        // 3:判断库存是否充足
        // if(num >  numstore ){ return  "商品库存不足..."; }
        // 4: 下单逻辑
        // orderService.saveOrder(order);
        // 5: 下单成功要扣减库存
        // 6: 下单完成以后
        System.out.println("用户 " + userId + ",订单编号是:" + orderNumer);
        String exchangeName = "topic_order_exchange";
//        String routeKey = "jack.weixin.sss";
        String routeKey = "com.email.duanxin";
        rabbitTemplate.convertAndSend(exchangeName, routeKey, orderNumer);
    }

3.3 消费者

// bindings其实就是用来确定队列和交换机绑定关系
@RabbitListener(bindings =@QueueBinding(
        // email.fanout.queue 是队列名字,这个名字你可以自定随便定义。
        value = @Queue(value = "email.topic.queue",autoDelete = "false"),
        // order.fanout 交换机的名字 必须和生产者保持一致
        exchange = @Exchange(value = "topic_order_exchange",
                // 这里是确定的rabbitmq模式是:fanout 是以广播模式 、 发布订阅模式
                type = ExchangeTypes.TOPIC),
        key = "#.email.#"
))
@Component
public class TopicEmailService {
    // @RabbitHandler 代表此方法是一个消息接收的方法。该不要有返回值
    @RabbitHandler
    public void messagerevice(String message){
        // 此处省略发邮件的逻辑
        System.out.println("topic-email-------------->" + message);
    }
}
// bindings其实就是用来确定队列和交换机绑定关系
@RabbitListener(bindings =@QueueBinding(
        // email.fanout.queue 是队列名字,这个名字你可以自定随便定义。
        value = @Queue(value = "sms.topic.queue",autoDelete = "false"),
        // order.fanout 交换机的名字 必须和生产者保持一致
        exchange = @Exchange(value = "topic_order_exchange",
                // 这里是确定的rabbitmq模式是:fanout 是以广播模式 、 发布订阅模式
                type = ExchangeTypes.TOPIC),
        key = "#.sms.#"
))
@Component
public class TopicSMSService {
    // @RabbitHandler 代表此方法是一个消息接收的方法。该不要有返回值
    @RabbitHandler
    public void messagerevice(String message){
        // 此处省略发邮件的逻辑
        System.out.println("topic-sms-------------->" + message);
    }
}
@RabbitListener(bindings =@QueueBinding(
        // email.fanout.queue 是队列名字,这个名字你可以自定随便定义。
        value = @Queue(value = "weixin.topic.queue",autoDelete = "false"),
        // order.fanout 交换机的名字 必须和生产者保持一致
        exchange = @Exchange(value = "topic_order_exchange",
                // 这里是确定的rabbitmq模式是:fanout 是以广播模式 、 发布订阅模式
                type = ExchangeTypes.TOPIC),
        key = "#.weixin.#"
))
@Component
public class TopicWeixinService {

    // @RabbitHandler 代表此方法是一个消息接收的方法。该不要有返回值
    @RabbitHandler
    public void messagerevice(String message){
        // 此处省略发邮件的逻辑
        System.out.println("topic-weixin-------------->" + message);
    }
}

4. 配置类VS注解

RabbitMQ 是一个开源的消息代理和队列服务器,用来实现应用程序之间的消息传递。在使用 RabbitMQ 时,配置类和注解是两种常见的配置方式。每种方式都有其优点和缺点。

4.1 配置类

  • 优点:
  1. 灵活性: 使用配置类可以非常灵活地定义复杂的队列、交换器、绑定等。
  2. 可重用性: 配置类可以被多个组件或服务复用。
  3. 易于管理: 当项目变得复杂时,配置类可以让配置项更加集中,易于管理和维护。
  4. 明确性: 配置类使得配置逻辑清晰可见,便于理解业务逻辑。
  5. 测试友好: 可以更容易地为配置类编写单元测试。
  • 缺点:
  1. 代码量: 相比于注解,配置类通常需要更多的代码来设置相同的配置。
  2. 学习曲线: 对于初学者来说,可能需要一些时间来掌握如何正确使用配置类进行配置。
  3. 分散注意力: 开发者需要在业务逻辑和服务配置之间切换,可能会稍微分散对主要业务的关注。

4.2 注解

优点:

  1. 简洁: 使用注解可以直接在类或方法上声明配置,减少模板代码,使代码更简洁。
  2. 快速开发: 对于简单的应用场景,注解可以帮助开发者快速完成配置,提高开发效率。
  3. 直观: 注解直接与相关的类或方法关联,使得配置意图一目了然。
  4. 集成良好: 在Spring框架中,注解方式可以很好地与Spring的其他功能(如AOP)结合使用。
    缺点:
  5. 扩展性: 当需求变更或系统规模扩大时,注解可能不足以应对复杂的配置需求。
  6. 隐式配置: 过多使用注解可能导致配置变得隐晦,不那么显而易见,这可能不利于后续的维护。
  7. 限制性: 注解提供的是预设好的配置选项,对于非标准配置支持不够灵活。
  8. 调试困难: 如果出现配置错误,注解方式可能不容易定位问题所在。

http://www.niftyadmin.cn/n/5683170.html

相关文章

结合创新!小波变换+注意力机制,实现100%分类准确率

小波变换是一种先进的信号分析技术,它擅长捕捉信号的局部特征,但有时可能会忽略数据中的关键信息。为了克服这一局限,我们引入了注意力机制,这一机制能够强化模型对数据重要部分的关注。通过将小波变换与注意力机制相结合&#xf…

unixODBC编程(四)插入数据

ODBC插入数据也有一定的步骤,我们先来看一下。 1. 分配一个语句句柄,使用SQLAllocHandle()函数,句柄类型为SQL_HANDLE_STMT。 2. 准备语句,使用SQLPrepare()函数。 3. 为绑定的变量赋值。 4. 绑定输入变量,使用SQL…

数学符号练习-常用导数与四则运算

前言 其实主要的目的是可以在文本中输出各种数学符号,便于以后用到的时候有现成的例子拿过来抄~~ 常用导数公式 序号公式1 ( C ) ′ 0 (C)0 (C)′02 ( x μ ) ′ μ ⋅ x μ − 1 (x^μ)μx^{μ-1} (xμ)′μ⋅xμ−13 ( s i n x ) ′ c o s x (sinx)cosx (sin…

YoloV10改进策略:BackBone改进|PoolFormer赋能YoloV10,视觉检测性能显著提升的创新尝试

摘要 在深度学习的广阔领域中,目标检测作为计算机视觉的基石任务之一,始终吸引着研究者的广泛关注。近期,我们大胆尝试将前沿的PoolFormer主干网络引入经典的目标检测框架YoloV10中,这一创新性融合不仅为YoloV10注入了新的活力,更在检测精度与效率上实现了双重飞跃,成为…

基于STM32的远程工业控制系统架构设计:MQTT通信、React界面与FreeRTOS优化的综合应用

一、项目概述 项目目标和用途 本项目旨在开发一个基于STM32单片机的远程工业控制系统。该系统能够通过互联网监控和控制工业设备,实时采集环境和设备状态数据,并将数据上传至云端以便进行数据分析和可视化。用户可以通过移动应用或网页界面远程操作设备…

Oracle(147)如何进行数据库升级?

数据库升级是一个复杂的过程,涉及到备份现有数据、安装新版本的数据库软件、迁移数据和应用程序的兼容性测试等步骤。这里以从较旧版本的MySQL升级到较新版本为例,提供一个概览性的指导步骤。请注意,具体步骤可能会因数据库的具体版本和操作系…

【源码+文档+调试讲解】基于微信小程序的医院医疗设备管理系统springboot

摘 要 相比于以前的传统手工管理方式,智能化的管理方式可以大幅降低医院的运营人员成本,实现了医院医疗设备的标准化、制度化、程序化的管理,有效地防止了医院医疗设备的随意管理,提高了信息的处理速度和精确度,能够及…

leetcode每日一题day16(24.9.26)——数组元素和与数字和的绝对差

思路&#xff1a;遍历数组在对数组元素进行求和时并使用while循环求数字和&#xff0c;由于对于一个数&#xff0c;其必定大于其个数位数字的和,所以可以直接对sum进行减 代码 int differenceOfSum(vector<int>& nums) {int ans 0;for (int x : nums) {ans x; // …