RabbitMQ(RabbitMQ的消息收发的模板工具:SpringAMQP)

前言

在做点评项目的过程中遇到了异步通信的问题,只是项目中是基于Redis实现的,最近也是准备投简历了,看了好多,发现大多数都是基于RabbitMQ实现的,来花个几个小时专门学习一下吧(我是跟着黑马程序员的课学的,大家也可以去看看视频)

目录

    • 前言
    • [1. 什么是SpringAMQP?🤔](#1. 什么是SpringAMQP?🤔)
      • [1.1 SpringAMQP提供了三个功能:](#1.1 SpringAMQP提供了三个功能:)
      • [1.2 主要核心组件](#1.2 主要核心组件)
      • [1.3 简单来讲📦 Spring AMQP 就是把下面图像中的过程用简单的代码实现了](#1.3 简单来讲📦 Spring AMQP 就是把下面图像中的过程用简单的代码实现了)
  • [2.下面来更深入的学习Spring AMQP帮助RabbitMQ收发消息的方式](#2.下面来更深入的学习Spring AMQP帮助RabbitMQ收发消息的方式)
    • 2.1:声明队列和交换机:
      • 2.1.1交换机的类型有四种:
      • 拓展🧩:
        • [1. Fanout Exchange(扇出交换机)🔊 广播专用!](#1. Fanout Exchange(扇出交换机)🔊 广播专用!)
        • [2. Direct Exchange(直连交换机)✅ 最常用!](#2. Direct Exchange(直连交换机)✅ 最常用!)
      • [2.1.2 Topic Exchange(主题交换机)🔍 最灵活!](#2.1.2 Topic Exchange(主题交换机)🔍 最灵活!)
      • [2.1.3 声明一个fanout类型的交换机](#2.1.3 声明一个fanout类型的交换机)
      • [2.1.4 声明一个Direct类型的交换机](#2.1.4 声明一个Direct类型的交换机)
      • 基于注解声明
    • [2.2 消息的接收和发送:](#2.2 消息的接收和发送:)
      • [2.2.1 Fanout交换机:](#2.2.1 Fanout交换机:)
      • [2.2.2 Direct交换机:](#2.2.2 Direct交换机:)
      • [2.2.3 Topic交换机:](#2.2.3 Topic交换机:)

1. 什么是SpringAMQP?🤔

前面讲了在RabbitMQ控制台操作收发消息,我们开发业务功能的时候,肯定不能这样,应该基于编程的方式

但RabbitMQ官方提供的Java客户端编码相对复杂 ,而Spring的官方刚好基于RabbitMQ提供了这样一套消息收发的模板工具:SpringAMQP

1.1 SpringAMQP提供了三个功能:

  • 自动声明队列、交换机及其绑定关系
  • 基于注解的监听器模式,异步接收消息
  • 封装了RabbitTemplate工具,用于发送消息

1.2 主要核心组件

  1. AmqpTemplate / RabbitTemplate
  • 用于发送和接收消息。
  • 类似于 JMS 中的 JmsTemplate。
  • 支持同步发送、异步发送、请求-响应模式
java 复制代码
rabbitTemplate.convertAndSend("exchangeName", "routingKey", message);
  1. MessageConverter
  • 负责 Java 对象与 AMQP 消息之间的转换。
  • 默认使用 SimpleMessageConverter(仅支持 String、byte[]、Serializable)。
  • 常用替代:Jackson2JsonMessageConverter(支持 JSON 序列化对象)。
  1. @RabbitListener
    声明式消费消息,类似 @JmsListener。
    自动注册监听器到容器中。
java 复制代码
@RabbitListener(queues = "myQueue")
public void handleMessage(MyMessage msg) {
    // 处理消息
}
  1. RabbitListenerContainerFactory
  • 用于创建监听器容器(如 SimpleMessageListenerContainer)。
  • 可配置并发消费者数、确认模式(acknowledge mode)、错误处理等

1.3 简单来讲📦 Spring AMQP 就是把下面图像中的过程用简单的代码实现了

  1. 连 RabbitMQ:不用自己写连接代码。
  2. 发消息:一行代码就能把"订单"发到交换机再有交换机转发到队列
java 复制代码
rabbitTemplate.convertAndSend("交换机名字","订单队列Key", "要发送的信息");
  1. 收消息:加个注解,自动监听队列并处理。
java 复制代码
@RabbitListener(queues = "订单队列")
public void handleOrder(String message) {
    System.out.println("收到订单:" + message);
}

SpringAMQP在发消息时要选择交换机,不同的交换机发消息的方式也不一样

2.下面来更深入的学习Spring AMQP帮助RabbitMQ收发消息的方式

要发送消息肯定要有交换机和队列:

2.1:声明队列和交换机:

2.1.1交换机的类型有四种:

  • Fanout:广播,将消息交给所有绑定到交换机的队列。我们最早在控制台使用的正是Fanout交换机
  • Direct:订阅,基于RoutingKey(路由key)发送给订阅了消息的队列
  • Topic:通配符订阅,与Direct类似,只不过RoutingKey可以使用通配符
  • Headers:头匹配,基于MQ的消息头匹配,用的较少。

拓展🧩:

1. Fanout Exchange(扇出交换机)🔊 广播专用!
  • 规则:只要队列绑定了这个交换机,就全部收到。
  • 特点:真正的"广播",速度最快(无需匹配)。

🌰 例子:

2. Direct Exchange(直连交换机)✅ 最常用!

规则:Routing Key 必须完全等于 绑定时指定的 key。

特点:一对一 or 一对多(多个队列用相同 key 绑定,可实现广播 )。

🌰 例子

注⚠️: Exchange不再把消息交给每一个绑定的队列,而是根据消息的Routing Key进行判断,只有队列的Routingkey与消息的 Routing key完全一致,才会接收到消息

2.1.2 Topic Exchange(主题交换机)🔍 最灵活!

  • 规则:Routing Key 是 点分字符串(如 "user.login.cn"),绑定时可用通配符:
    *:匹配一个单词(不能跨点)
    #:匹配零个或多个单词(可跨点)

🌰 通配符示例:

Routing Key 是否匹配*.login.* 是否匹配 user.#
user.login.cn ✅ 是 ✅ 是
admin.login.us ✅ 是 ❌ 否(不是 user 开头
user.action.view ❌ 否 ✅ 是

⚠️注:Exchange(交换机)只负责转发消息,不具备存储消息的能力

2.1.3 声明一个fanout类型的交换机

java 复制代码
package com.itheima.consumer.config;

import ...

@Configuration
public class FanoutConfig {
    /**
     * 声明交换机
     * @return Fanout类型交换机
     */
    @Bean
    public FanoutExchange fanoutExchange(){
        return new FanoutExchange("hmall.fanout");
    }

    /**
     * 第1个队列
     */
    @Bean
    public Queue fanoutQueue1(){
        return new Queue("fanout.queue1");
    }

    /**
     * 绑定队列和交换机
     */
    @Bean
    public Binding bindingQueue1(Queue fanoutQueue1, FanoutExchange fanoutExchange){
        return BindingBuilder.bind(fanoutQueue1).to(fanoutExchange);
    }

    /**
     * 第2个队列
     */
    @Bean
    public Queue fanoutQueue2(){
        return new Queue("fanout.queue2");
    }

    /**
     * 绑定队列和交换机
     */
    @Bean
    public Binding bindingQueue2(Queue fanoutQueue2, FanoutExchange fanoutExchange){
        return BindingBuilder.bind(fanoutQueue2).to(fanoutExchange);
    }
}

2.1.4 声明一个Direct类型的交换机

java 复制代码
@Configuration
public class RabbitConfig {

    // 1. 声明一个队列
    @Bean
    public Queue orderQueue() {
        return new Queue("order.queue", true); // true = 持久化(重启不丢)
    }

    // 2. 声明一个 Direct 类型的交换机
    @Bean
    public DirectExchange orderExchange() {
        return new DirectExchange("order.exchange");
    }

    // 3. 把队列绑定到交换机,用 routing key "create.order"
    @Bean
    public Binding orderBinding() {
        return BindingBuilder
                .bind(orderQueue())
                .to(orderExchange())
                .with("create.order");
    }
}

基于@Bean的方式声明队列和交换机比较麻烦,Spring还提供了基于注解方式来声明

基于注解声明

java 复制代码
@RabbitListener(bindings = @QueueBinding(
    value = @Queue(name = "direct.queue1"),
    exchange = @Exchange(name = "hmall.direct", type = ExchangeTypes.DIRECT),
    key = {"red", "blue"}
))
public void listenDirectQueue1(String msg){
    System.out.println("消费者1接收到direct.queue1的消息:【" + msg + "】");
}

@RabbitListener(bindings = @QueueBinding(
    value = @Queue(name = "direct.queue2"),
    exchange = @Exchange(name = "hmall.direct", type = ExchangeTypes.DIRECT),
    key = {"red", "yellow"}
))
public void listenDirectQueue2(String msg){
    System.out.println("消费者2接收到direct.queue2的消息:【" + msg + "】");
}

@RabbitListener(bindings = @QueueBinding(
    value = @Queue(name = "topic.queue1"),
    exchange = @Exchange(name = "hmall.topic", type = ExchangeTypes.TOPIC),
    key = "china.#"
))
public void listenTopicQueue1(String msg){
    System.out.println("消费者1接收到topic.queue1的消息:【" + msg + "】");
}

@RabbitListener(bindings = @QueueBinding(
    value = @Queue(name = "topic.queue2"),
    exchange = @Exchange(name = "hmall.topic", type = ExchangeTypes.TOPIC),
    key = "#.news"
))
public void listenTopicQueue2(String msg){
    System.out.println("消费者2接收到topic.queue2的消息:【" + msg + "】");
}

2.2 消息的接收和发送:

2.2.1 Fanout交换机:

消息发送

java 复制代码
@Test
public void testFanoutExchange() {
    // 交换机名称
    String exchangeName = "hmall.fanout";
    // 消息
    String message = "hello, everyone!";
    rabbitTemplate.convertAndSend(exchangeName, "", message);
}

消息接收

java 复制代码
@RabbitListener(queues = "fanout.queue1")
public void listenFanoutQueue1(String msg) {
    System.out.println("消费者1接收到Fanout消息:【" + msg + "】");
}

@RabbitListener(queues = "fanout.queue2")
public void listenFanoutQueue2(String msg) {
    System.out.println("消费者2接收到Fanout消息:【" + msg + "】");
}

2.2.2 Direct交换机:

接受消息:

java 复制代码
@RabbitListener(queues = "direct.queue1")
public void listenDirectQueue1(String msg) {
    System.out.println("消费者1接收到direct.queue1的消息:【" + msg + "】");
}

@RabbitListener(queues = "direct.queue2")
public void listenDirectQueue2(String msg) {
    System.out.println("消费者2接收到direct.queue2的消息:【" + msg + "】");
}

消息发送:

java 复制代码
@Test
public void testSendDirectExchange() {
    // 交换机名称
    String exchangeName = "hmall.direct";
    // 消息
    String message = "红红火火";
    // 发送消息
    rabbitTemplate.convertAndSend(exchangeName, "red", message);
}

2.2.3 Topic交换机:

消息发送

java 复制代码
/**
 * topicExchange
 */
@Test
public void testSendTopicExchange() {
    // 交换机名称
    String exchangeName = "hmall.topic";
    // 消息
    String message = "hhhhhhhhhhh";
    // 发送消息
    rabbitTemplate.convertAndSend(exchangeName, "china.news", message);
}

消息接收

java 复制代码
@RabbitListener(queues = "topic.queue1")
public void listenTopicQueue1(String msg){
    System.out.println("消费者1接收到topic.queue1的消息:【" + msg + "】");
}

@RabbitListener(queues = "topic.queue2")
public void listenTopicQueue2(String msg){
    System.out.println("消费者2接收到topic.queue2的消息:【" + msg + "】");
}

小白啊!!!写的不好轻喷啊🤯如果觉得写的不好,点个赞吧🤪(批评是我写作的动力)

。。。。。。。。。。。。。。

。。。。。。。。。。。。。。。

相关推荐
用户83071968408216 小时前
RabbitMQ vs RocketMQ 事务大对决:一个在“裸奔”,一个在“开挂”?
后端·rabbitmq·rocketmq
初次攀爬者2 天前
RabbitMQ的消息模式和高级特性
后端·消息队列·rabbitmq
初次攀爬者4 天前
ZooKeeper 实现分布式锁的两种方式
分布式·后端·zookeeper
让我上个超影吧5 天前
消息队列——RabbitMQ(高级)
java·rabbitmq
塔中妖5 天前
Windows 安装 RabbitMQ 详细教程(含 Erlang 环境配置)
windows·rabbitmq·erlang
断手当码农5 天前
Redis 实现分布式锁的三种方式
数据库·redis·分布式
初次攀爬者5 天前
Redis分布式锁实现的三种方式-基于setnx,lua脚本和Redisson
redis·分布式·后端
业精于勤_荒于稀5 天前
物流订单系统99.99%可用性全链路容灾体系落地操作手册
分布式
Ronin3055 天前
信道管理模块和异步线程模块
开发语言·c++·rabbitmq·异步线程·信道管理
Asher05095 天前
Hadoop核心技术与实战指南
大数据·hadoop·分布式