SpringBoot 整合 RabbitMQ 的使用

一、RabbitTemplate 的使用

1.【导入依赖】

<!-- rabbitMQ -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-amqp</artifactId>
    <version>2.6.1</version>
</dependency>

2.【添加配置】

rabbitmq:
    host:   #ip地址
    port: 5672 #端口
    username: guest
    password: guest
    virtual-host: /
    listener:
      simple:
        prefetch: 1 # 默认每次取出一条消息消费, 消费完成取下一条
        acknowledge-mode: manual # 设置消费端手动ack确认
        retry:
          enabled: true # 是否支持重试
    publisher-confirm-type: correlated  #确认消息已发送到交换机(Exchange)
    publisher-returns: true  #确认消息已发送到队列(Queue)

3.【点对点通信(队列模式)(Point-to-Point Messaging)】

使用方式:

这种方式也被称为队列(Queue)模型。消息发送者(Producer)发送消息到队列,然后消息接收者(Consumer)从队列中获取消息进行处理。这种模型下,每个消息只有一个消费者可以接收,确保消息的可靠传递和顺序处理。

代码示例:

生产者
java 复制代码
    /**
     * 第一种模型: 简单模型
     * 一个消息生产者  一个队列  一个消费者
     * @return
     */
    @GetMapping("hello/world")
    public void helloWorld() {
        SysUser sysUser = new SysUser();
        // 发送消息
        // 第一个参数: String routingKey 路由规则 【交换机 和队列的绑定规则 】  队列名称
        // 第二个参数: object message 消息的内容
//        rabbitTemplate.convertAndSend("hello_world_queue", "hello world rabbit!");
        ///  MessagePostProcessor 消息包装器  如果需要对消息进行包装
        rabbitTemplate.convertAndSend("hello_world_queue", "hello world rabbit!", message -> {
            // 设置唯一的标识
            message.getMessageProperties().setMessageId(UUID.randomUUID().toString());
            return message;
        });
消费者
java 复制代码
import com.rabbitmq.client.Channel;
import lombok.extern.log4j.Log4j2;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.annotation.Queue;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;

@Component
@Log4j2
public class HelloWorldConsumer {

    @Autowired
    private StringRedisTemplate redisTemplate;

    /**
     * 监听 hello_world_queue 队列消费消息
     * queues 监听队列的名称  要求这个队列必须是已经存在的队列
     * queuesToDeclare 监听队列 如果这个队列不存在 则 rabbitMQ 中 RabbitAdmin 会帮助去构建这个队列
     */
    @RabbitListener(queuesToDeclare = @Queue("hello_world_queue"))
    public void helloWorldConsumer(String msg, Message message, Channel channel) {
        // 获取消息的唯一标识
        String messageId = message.getMessageProperties().getMessageId();
        // 将消息添加到 Redis的set集合中  set 不能重复的  方法的返回值 添加成功的数量
        Long count = redisTemplate.opsForSet().add("hello_world_queue", messageId);
        if (count != null && count == 1) {
            // 没有消费过   正常消费
            log.info("hello_world_queue队列消费者接收到了消息,消息内容:{}", message);
        }
    }

}

4.【发布/订阅模式(Publish/Subscribe Messaging)】

使用方式:

在发布/订阅模式中,消息发送者将消息发布到交换机(Exchange),而不是直接发送到队列。交换机负责将消息路由到一个或多个绑定的队列中。每个订阅者(Subscriber)可以选择订阅它感兴趣的消息队列,从而接收消息。

代码示例:

生产者
java 复制代码
/**
 * 工作队列
 * 一个生产者  一个队列  多个消费者
 */
@GetMapping("work/queue")
public void workQueue() {
    for (int i = 1; i <= 10; i++) {
        rabbitTemplate.convertAndSend("work_queue", i + "hello work queue!");
    }
}
消费者
java 复制代码
import lombok.extern.log4j.Log4j2;
import org.springframework.amqp.rabbit.annotation.Queue;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Component;


@Component
@Log4j2
public class WorkQueueConsumer {

    /***
     * 消费者1
     * @param message
     */
    @RabbitListener(queuesToDeclare = @Queue("work_queue"))
    public void workQueueConsumer(String message) throws InterruptedException {
        Thread.sleep(200);
        log.info("work_queue队列消费者1接收到了消息,消息内容:{}", message);
    }

    /***
     * 消费者2
     * @param message
     */
    @RabbitListener(queuesToDeclare = @Queue("work_queue"))
    public void workQueueConsumer2(String message) throws InterruptedException {
        Thread.sleep(400);
        log.info("work_queue队列消费者2接收到了消息,消息内容:{}", message);
    }
}

5.【工作队列模式(Work Queues)】

使用方式:

工作队列模式也称为任务队列(Task Queues),它可以用来实现任务的异步处理。多个工作者(Worker)同时监听同一个队列,当有新的任务消息被发送到队列中时,空闲的工作者会获取并处理这些任务,确保任务能够并行处理而不会重复执行。

代码示例:

生产者
java 复制代码
/**
 * 发布订阅
 * 一个生产者  多个队列   多个消费者   涉及 到交换机  fanout
 */
@GetMapping("publish/subscribe")
public void publishSubscribe() {
    // 第一个参数: 交换机的名称  没有要求
    // 第二个参数: 交换机和队列的绑定规则    如果是发布订阅模式 那么这个规则默认不写 只需要交换机和队列绑定即可不需要规则
    // 第三个参数: 消息内容
    rabbitTemplate.convertAndSend("publish_subscribe_exchange", "",
            "hello publisher subscribe!!");
}
消费者
java 复制代码
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.amqp.core.ExchangeTypes;
import org.springframework.amqp.rabbit.annotation.Exchange;
import org.springframework.amqp.rabbit.annotation.Queue;
import org.springframework.amqp.rabbit.annotation.QueueBinding;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Component;


@Component
public class PublisherSubscribeConsumer {

    private static final Logger log = LoggerFactory.getLogger(PublisherSubscribeConsumer.class);

    /**
     * 发布订阅模型消费者
     *
     * @param message
     */
    @RabbitListener(bindings = @QueueBinding(value = @Queue("pb_sb_queue_01"),
            exchange = @Exchange(name = "publish_subscribe_exchange",
                    type = ExchangeTypes.FANOUT)))
    public void publisherSubscribe(String message) {
        log.info("发布订阅模型消费者1接收到了消息,消息内容:{}", message);
    }

    /**
     * 发布订阅模型消费者
     *
     * @param message
     */
    @RabbitListener(bindings = @QueueBinding(value = @Queue("pb_sb_queue_02"),
            exchange = @Exchange(name = "publish_subscribe_exchange", type = ExchangeTypes.FANOUT)))
    public void publisherSubscribe2(String message) {
        log.info("发布订阅模型消费者2接收到了消息,消息内容:{}", message);
    }

}

6.【路由模式(Routing)】

使用方式:

路由模式允许发送者根据消息的路由键(Routing Key)将消息路由到特定的队列。发送者将消息发送到交换机,并且通过设置不同的路由键,使消息能够被交换机路由到不同的队列。消费者可以根据需要选择监听哪些队列来接收消息。

代码示例:

生产者
java 复制代码
/**
 * 路由模型
 * 一个生产者  多个队列   多个消费者   涉及 到交换机  direct
 */
@GetMapping("routing")
public void routing() {
    // 第一个参数: 交换机的名称  没有要求
    // 第二个参数: 交换机和队列的绑定规则    字符串 随意
    // 第三个参数: 消息内容
    rabbitTemplate.convertAndSend("routing_exchange", "aaa",
            "hello routing!!");
}
消费者
java 复制代码
import lombok.extern.log4j.Log4j2;
import org.springframework.amqp.core.ExchangeTypes;
import org.springframework.amqp.rabbit.annotation.Exchange;
import org.springframework.amqp.rabbit.annotation.Queue;
import org.springframework.amqp.rabbit.annotation.QueueBinding;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Component;

@Component
@Log4j2
public class RoutingConsumer {

    /**
     * 路由模型消费者
     * @param message
     */
    @RabbitListener(bindings = @QueueBinding(value = @Queue("routing_queue_01"),
            exchange = @Exchange(name = "routing_exchange", type = ExchangeTypes.DIRECT),
            key = { "abc", "error", "info" }))
    public void routingConsumer(String message) {
        log.info("路由模型消费者1接收到了消息,消息内容:{}", message);
    }

    /**
     * 路由模型消费者
     * @param message
     */
    @RabbitListener(bindings = @QueueBinding(value = @Queue("routing_queue_02"),
            exchange = @Exchange(name = "routing_exchange", type = ExchangeTypes.DIRECT),
            key = { "aaa", "ccc", "waadaffas" }))
    public void routingConsumer2(String message) {
        log.info("路由模型消费者2接收到了消息,消息内容:{}", message);
    }

    /**
     * 路由模型消费者
     * @param message
     */
    @RabbitListener(bindings = @QueueBinding(value = @Queue("routing_queue_03"),
            exchange = @Exchange(name = "routing_exchange", type = ExchangeTypes.DIRECT),
            key = { "bbbb", "asdfasd", "asdfasdf" }))
    public void routingConsumer3(String message) {
        log.info("路由模型消费者3接收到了消息,消息内容:{}", message);
    }


}

7.【主题模式(Topics)】

使用方式:

主题模式是路由模式的一种扩展,它允许发送者根据消息的多个属性(如主题)将消息路由到一个或多个队列。主题交换机(Topic Exchange)使用通配符匹配路由键与队列绑定键的模式,从而实现更灵活的消息路由和过滤。

代码示例:

生产者
java 复制代码
/**
 * 主题模型
 * 一个生产者  多个队列   多个消费者   涉及 到交换机  topic
 */
@GetMapping("topic")
public void topic() {
    // 第一个参数: 交换机的名称  没有要求
    // 第二个参数: 交换机和队列的绑定规则    多个单词  以 "." 拼起来
    // 第三个参数: 消息内容
    rabbitTemplate.convertAndSend("topic_exchange", "bwie.age.name",
            "hello topic!!");
}
消费者
java 复制代码
import lombok.extern.log4j.Log4j2;
import org.springframework.amqp.core.ExchangeTypes;
import org.springframework.amqp.rabbit.annotation.Exchange;
import org.springframework.amqp.rabbit.annotation.Queue;
import org.springframework.amqp.rabbit.annotation.QueueBinding;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Component;


@Component
@Log4j2
public class TopicConsumer {

    /**
     * *  表示任意一个单词
     * #  表示任意一个单词 或 多个
     */
    @RabbitListener(bindings = @QueueBinding(value = @Queue(name = "topic_queue_01"),
            exchange = @Exchange(name = "topic_exchange", type = ExchangeTypes.TOPIC),
            key = { "abc.*", "error.*.info", "#.name" }))
    public void topicConsumer(String message) {
        log.info("xxxxxxxxx1");
    }

    /**
     * *  表示任意一个单词
     * #  表示任意一个单词 或 多个
     */
    @RabbitListener(bindings = @QueueBinding(value = @Queue(name = "topic_queue_02"),
            exchange = @Exchange(name = "topic_exchange", type = ExchangeTypes.TOPIC),
            key = { "abc.*", "username" }))
    public void topicConsumer2(String message) {
        log.info("xxxxxxxxx2");
    }


    /**
     * *  表示任意一个单词
     * #  表示任意一个单词 或 多个
     */
    @RabbitListener(bindings = @QueueBinding(value = @Queue(name = "topic_queue_03"),
            exchange = @Exchange(name = "topic_exchange", type = ExchangeTypes.TOPIC),
            key = { "bwie.*", "error.*.info" }))
    public void topicConsumer3(String message) {
        log.info("xxxxxxxxx3");
    }

}
相关推荐
向前看-1 小时前
验证码机制
前端·后端
xlsw_1 小时前
java全栈day20--Web后端实战(Mybatis基础2)
java·开发语言·mybatis
神仙别闹2 小时前
基于java的改良版超级玛丽小游戏
java
黄油饼卷咖喱鸡就味增汤拌孜然羊肉炒饭3 小时前
SpringBoot如何实现缓存预热?
java·spring boot·spring·缓存·程序员
暮湫3 小时前
泛型(2)
java
超爱吃士力架3 小时前
邀请逻辑
java·linux·后端
南宫生3 小时前
力扣-图论-17【算法学习day.67】
java·学习·算法·leetcode·图论
转码的小石3 小时前
12/21java基础
java
李小白663 小时前
Spring MVC(上)
java·spring·mvc
GoodStudyAndDayDayUp4 小时前
IDEA能够从mapper跳转到xml的插件
xml·java·intellij-idea