Springboot整合RabbitMQ,生产者和消息者详细教程(附git源码+延迟、通配符、topic、临时、死信队列案例)

Springboot-cli 开发脚手架系列



简介

  • Springboot整合RabbitMQ,消息者及生成者完整案例
    包含多种队列使用案例
  • 普通队列
  • 延迟队列
  • 通配符队列
  • topic队列
  • 临时队列
  • 死信队列

RabbitMQ参数说明

  • x-message-ttl 发送到队列的消息在丢弃之前可以存活多长时间(毫秒)。
  • x-expires 队列在被⾃动删除(毫秒)之前可以使⽤多长时间。
  • x-max-length 队列在开始从头部删除之前可以包含多少就绪消息。
  • x-max-length-bytes 队列在开始从头部删除之前可以包含的就绪消息的总体⼤⼩。
  • x-dead-letter-exchange 设置队列溢出⾏为。这决定了在达到队列的最⼤长度时消息会发⽣什么。有效值为drop-head或
    reject-publish。交换的可选名称,如果消息被拒绝或过期,将重新发布这些名称。
  • x-dead-letter-routing-key 可选的替换路由密钥,⽤于在消息以字母为单位时使⽤。如果未设置,将使⽤消息的原始路由密钥。
  • x-max-priority 队列⽀持的最⼤优先级数;如果未设置,队列将不⽀持消息优先级。
  • x-queue-mode 将队列设置为延迟模式,在磁盘上保留尽可能多的消息以减少内存使⽤;如果未设置,队列将保留内存缓存以尽
    快传递消息。
  • x-queue-master-locator 将队列设置为主位置模式,确定在节点集群上声明时队列主机所在的规则

1. 环境

       <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-amqp</artifactId>
        </dependency>

2. 常量配置-定义队列

  • 队列定义
public class RabbitDefine {

    /**
     * 普通交换机
     */
    public final static String DIRECT_EXCHANGE = "direct.exchange";

    /**
     * 普通队列
     */
    public final static String DIRECT_QUEUE = "direct.queue";

    /**
     * 延迟队列交换机
     */
    public final static String DELAY_EXCHANGE = "delay.exchange";

    /**
     * 延迟队列
     */
    public final static String DELAY_QUEUE = "delay.queue";

    /**
     * 通配符交换机
     */
    public final static String FANOUT_EXCHANGE = "fanout.exchange";

    /**
     * 通配符队列
     */
    public final static String FANOUT_QUEUE = "fanout.queue";

    /**
     * topic 交换器
     */
    public final static String TOPIC_EXCHANGE = "topic.exchange";

    /**
     * topic队列1
     */
    public final static String TOPIC_QUEUE_ONE = "topic.queue.one";

    /**
     * topic队列2
     */
    public final static String TOPIC_QUEUE_TWO = "topic.queue.two";

    /**
     * 临时队列交换器
     */
    public final static String TTL_EXCHANGE = "ttl.exchange";

    /**
     * 临时队列
     */
    public final static String TTL_QUEUE = "ttl.queue";

    /**
     * 死信交换机
     */
    public final static String DEAD_EXCHANGE = "dead.exchange";

    /**
     * 死信队列
     */
    public final static String DEAD_QUEUE = "dead.queue";
}

3. 提供者

环境配置 开启手动提交ack消息模式

spring:
  application:
    name: rabbitmq-producer
  rabbitmq:
    host: 192.168.41.128
    port: 5672
    username: guest
    password: guest
    virtualHost: /
    # 手动提交ack消息
    listener:
      simple:
        acknowledge-mode: manual
      direct:
        acknowledge-mode: manual
3.1 direct消息队列配置
  • Direct 类型的交换器由路由规则很简单,它会把消息路由到那些 BindingKey 和 RoutingKey 完全匹配的队列中。Direct Exchange 是 RabbitMQ 默认的交换器模式,也是最简单的模式。它根据 RoutingKey 完全匹配去寻找队列。
@Configuration
public class RabbitDirectConfig {

    /**
     * 创建direct Exchange交换机也叫完全匹配交换机
     */
    @Bean
    public DirectExchange directExchange() {
        return ExchangeBuilder
                .directExchange(RabbitDefine.DIRECT_EXCHANGE)
                // 开启持久化
                .durable(true)
                .build();
    }

    /**
     * 普通队列
     */
    @Bean
    public Queue directQueue() {
        return QueueBuilder
                .durable(RabbitDefine.DIRECT_QUEUE)
                .build();
    }

    /**
     * 交换机绑定队列
     */
    @Bean
    public Binding directBinding() {
        return BindingBuilder.bind(directQueue()).to(directExchange()).with("direct");
    }


}
3.2 通配符队列
  • 发送到交换机的消息会被转发到与该交换机绑定的所有队列上。消息广播。Fanout交换机转发消息是最快的。
@Configuration
public class RabbitFanoutConfig {

    /**
     * 创建Fanout Exchange交换机也叫通配符交换机
     */
    @Bean
    public FanoutExchange fanoutExchange() {
        return ExchangeBuilder
                .fanoutExchange(RabbitDefine.FANOUT_EXCHANGE)
                // 开启持久化
                .durable(true)
                .build();
    }

    /**
     * 创建队列
     */
    @Bean
    public Queue fanoutQueue() {
        return QueueBuilder
                .durable(RabbitDefine.FANOUT_QUEUE)
                .build();
    }

    /**
     * 确定绑定关系,队列和交换机绑定
     */
    @Bean
    public Binding fanoutBinding() {
        return BindingBuilder.bind(fanoutQueue()).to(fanoutExchange());
    }

}
3.3 Topic队列
  • topic与direct类型的交换器类似,也是将消息路由到RoutingKey与BindingKey匹配的队列中,但它不是完全匹配,而是模糊匹配。
  • 规则:#用于匹配一个单词,用于匹配多个单词(可以是0个);例如:order..current。
@Configuration
public class RabbitTopicConfig {

    /**
     * 创建Topic Exchange交换机也叫模糊匹配交换机
     */
    @Bean
    public TopicExchange topicExchange() {
        return ExchangeBuilder
                .topicExchange(RabbitDefine.TOPIC_EXCHANGE)
                // 开启持久化
                .durable(true)
                .build();
    }

    /**
     * 创建队列 1
     */
    @Bean
    public Queue topicOneQueue() {
        return QueueBuilder
                .durable(RabbitDefine.TOPIC_QUEUE_ONE)
                .build();
    }

    /**
     * 创建队列 2
     */
    @Bean
    public Queue topicTwoQueue() {
        return QueueBuilder
                .durable(RabbitDefine.TOPIC_QUEUE_TWO)
                .build();
    }

    /**
     * 确定绑定关系
     * #用于匹配一个单词 *用于匹配多个单词
     */
    @Bean
    public Binding topicOneBinding(@Qualifier("topicOneQueue") Queue topicQueue, @Qualifier("topicExchange") TopicExchange topicExchange) {
        return BindingBuilder.bind(topicQueue).to(topicExchange).with("#.queue.one");
    }

    @Bean
    public Binding topicTwoBinding(@Qualifier("topicTwoQueue") Queue topicQueue, @Qualifier("topicExchange") TopicExchange topicExchange) {
        return BindingBuilder.bind(topicQueue).to(topicExchange).with("#.queue.*");
    }

}
3.4 延迟队列
  • 消息延期到达
@Configuration
public class RabbitDelayConfig {


    /**
     * 创建延时交换机
     */
    @Bean
    public DirectExchange delayExchange() {
        return ExchangeBuilder
                .directExchange(RabbitDefine.DELAY_EXCHANGE)
                // 开启延时
                .delayed()
                // 开启持久化
                .durable(true)
                .build();
    }

    /**
     * 队列
     */
    @Bean
    public Queue delayQueue() {
        return QueueBuilder
                .durable(RabbitDefine.DELAY_QUEUE)
                .build();
    }

    /**
     * 交换机绑定队列
     */
    @Bean
    public Binding delayBinding() {
        return BindingBuilder.bind(delayQueue()).to(delayExchange()).with("delay");
    }

}
3.5 死信队列
  • 当消息过期时,消息进入死信队列
@Configuration
public class RabbitDeadConfig {

    /**
     * 死信交换机
     *
     * @return FanoutExchange
     */
    @Bean
    public DirectExchange deadExchange() {
        return ExchangeBuilder.directExchange(RabbitDefine.DEAD_EXCHANGE)
                // 开启持久化
                .durable(true)
                // 所有消费者都解除订阅此队列,autoDelete=true时,此队列会自动删除
                .autoDelete()
                .build();
    }

    /**
     * 死信队列
     *
     * @return Queue
     */
    @Bean
    public Queue deadQueue() {
        return QueueBuilder.durable(RabbitDefine.DEAD_QUEUE).build();
    }

    /**
     * 绑定
     *
     * @return Binding
     */
    @Bean
    public Binding deadBinding(@Qualifier("deadExchange") DirectExchange deadExchange, @Qualifier("deadQueue") Queue deadQueue) {
        return BindingBuilder.bind(deadQueue).to(deadExchange).with("dead");
    }

}

3.6 临时队列
  • 消息设置过期时间,过期消息转入死信队列
@Configuration
public class RabbitTtlDirectConfig {

    /**
     * 创建交换机
     */
    @Bean
    public DirectExchange directTtlExchange() {
        return ExchangeBuilder
                .directExchange(RabbitDefine.TTL_EXCHANGE)
                // 开启持久化
                .durable(true)
                // 所有消费者都解除订阅此队列,autoDelete=true时,此交换机会自动删除
                //.autoDelete()
                .build();
    }

    /**
     * 会过期的队列
     */
    @Bean
    public Queue directTtlQueue() {

        return QueueBuilder.
                durable(RabbitDefine.TTL_QUEUE)
                // 设置队列的过期时间为10秒
                .ttl(10000)
                // 配置消息过期后的处理者(死信队列交换机)
                .deadLetterExchange(RabbitDefine.DEAD_EXCHANGE)
                // 死信队列路由
                .deadLetterRoutingKey("dead")
                // 所有消费者都解除订阅此队列,autoDelete=true时,此交换机会自动删除
                // .autoDelete()
                .build();
    }

    @Bean
    public Binding directTtlBinding() {
        return BindingBuilder.bind(directTtlQueue()).to(directTtlExchange()).with("test");
    }

}

4. 消息发送测试

  • 消息提供者
@Component
@RequiredArgsConstructor
@Slf4j
public class RabbitProducer {

    private final RabbitTemplate rabbitTemplate;

    /**
     * 直接模式发送消息
     *
     * @param message 发送的信息
     */
    public void sendDirect(Object message) {
        rabbitTemplate.convertAndSend(RabbitDefine.DIRECT_QUEUE, message, this.getCorrelationData());
    }

    /**
     * 分裂模式发送消息
     *
     * @param message 发送的信息
     */
    public void sendFanout(Object message) {
        rabbitTemplate.convertAndSend(RabbitDefine.FANOUT_EXCHANGE, "", message);
    }


    /**
     * 主题模式发送消息
     *
     * @param message    发送的信息
     * @param routingKey 匹配的队列名
     */
    public void sendTopic(Object message, String routingKey) {
        rabbitTemplate.convertAndSend(RabbitDefine.TOPIC_EXCHANGE, routingKey, message);
    }


    /**
     * 发送延迟消息
     *
     * @param message 发送的信息
     * @param delay   延迟时间ms
     */
    public void sendDelay(String message, int delay) {
        rabbitTemplate.convertAndSend(RabbitDefine.DELAY_EXCHANGE, "delay", message, msg -> {
            msg.getMessageProperties().setDelay(delay);
            return msg;
        });
    }

    /**
     * 发送临时消息10s过期
     */
    public void sendAndExpire(Object message) {
        rabbitTemplate.convertAndSend(RabbitDefine.TTL_QUEUE, message, this.getCorrelationData());
    }

    /**
     * 生成消息标识
     */
    private CorrelationData getCorrelationData() {
        String messageId = UUID.randomUUID().toString();
        CorrelationData correlationData = new CorrelationData();
        correlationData.setId(messageId);
        return correlationData;
    }

}
  • 编写测试方法
@SpringBootTest
@Slf4j
public class ProducerTest {

    @Autowired
    RabbitProducer rabbitProducer;

    @Test
    void sendDirect() {
        rabbitProducer.sendDirect("直通消息9527!");
    }

    @Test
    void sendFanout() {
        rabbitProducer.sendFanout("分裂消息6666!");
    }

    @Test
    void sendAndExpire() {
        rabbitProducer.sendAndExpire("晚上10点老地方不见不散!该消息有效期10秒");
    }

    @Test
    void sendDelay() {
        rabbitProducer.sendDelay("有内鬼,终止交易~~", 5000);
    }


    @Test
    void sendTopic() {
        rabbitProducer.sendTopic("放学别走!", "test123.topic.test456");
    }
}

5. 消费者

  • yml配置
spring:
  application:
    name: rabbitmq-consumer
  rabbitmq:
    host: 192.168.41.128
    port: 5672
    username: guest
    password: guest
    virtualHost: /
    # 手动提交ack消息
    listener:
      simple:
        acknowledge-mode: manual
      direct:
        acknowledge-mode: manual
  • 注解方式实现消息监听
@Component
@Slf4j
public class RabbitConsumer {

    /**
     * 普通消息
     */
    @RabbitListener(queuesToDeclare = @Queue(RabbitDefine.DIRECT_QUEUE))
    public void consumer1(String message, Channel channel, @Header(AmqpHeaders.DELIVERY_TAG) long tag) throws IOException {
        log.info("消费者1(直通消息)-队列索引:{},接收到消息:{}", tag, message);
        channel.basicAck(tag, false);
    }

    /**
     * 分裂消息
     */
    @RabbitListener(queuesToDeclare = @Queue(RabbitDefine.FANOUT_QUEUE))
    public void consumer2(String message, Channel channel, @Header(AmqpHeaders.DELIVERY_TAG) long tag) throws IOException {
        log.info("消费者2(分裂消息)-队列索引:{},接收到消息:{}", tag, message);
        channel.basicAck(tag, false);
    }

    /**
     * 临时消息
     */
    @RabbitListener(bindings = {
            @QueueBinding(
                    value = @Queue(value = RabbitDefine.TTL_QUEUE,
                            arguments = {
                                    // 指定一下死信交换机
                                    @Argument(name = "x-dead-letter-exchange", value = RabbitDefine.DEAD_EXCHANGE),
                                    // 指定死信交换机的路由key
                                    @Argument(name = "x-dead-letter-routing-key", value = "dead"),
                                    // 指定队列的过期时间
                                    @Argument(name = "x-message-ttl", value = "10000", type = "java.lang.Long")
                            }),
                    exchange = @Exchange(name = RabbitDefine.TTL_EXCHANGE),
                    key = "test"
            )
    })
    public void consumer3(String message, Channel channel, @Header(AmqpHeaders.DELIVERY_TAG) long tag) throws IOException {
        log.info("消费者3(临时消息)-队列索引:{},接收到消息:{}", tag, message);
        channel.basicAck(tag, false);
    }

    /**
     * 延时消息
     */
    @RabbitListener(bindings = @QueueBinding(
            value = @Queue(name = RabbitDefine.DELAY_QUEUE),
            exchange = @Exchange(name = RabbitDefine.DELAY_EXCHANGE, delayed = "true"),
            key = "delay"))
    public void consumer4(String message, Channel channel, @Header(AmqpHeaders.DELIVERY_TAG) long tag) throws IOException {
        log.info("消费者4(延时队列)-队列索引:{},接收到消息:{}", tag, message);
        try {
            // 接收成功
            channel.basicAck(tag, false);
        } catch (Exception e) {
            log.error("发生异常,消息签收失败");
            // 第三个参数 requeue = true为将消息重返当前消息队列,还可以重新发送给消费者
            channel.basicNack(tag, false, true);
        }
    }

    /**
     * topic消息1
     */
    @RabbitListener(bindings = @QueueBinding(
            value = @Queue(value = RabbitDefine.TOPIC_QUEUE_ONE, autoDelete = "false", durable = "true"),
            exchange = @Exchange(value = RabbitDefine.TOPIC_EXCHANGE, type = ExchangeTypes.TOPIC),
            key = "#.topic.#"
    ))
    public void consumer5(String message, Channel channel, @Header(AmqpHeaders.DELIVERY_TAG) long tag) throws IOException {
        log.info("消费者5(topic模式one)-队列索引:{},接收到消息:{}", tag, message);
        channel.basicAck(tag, false);
    }

    /**
     * topic消息2
     */
    @RabbitListener(bindings = @QueueBinding(
            value = @Queue(value = RabbitDefine.TOPIC_QUEUE_TWO, autoDelete = "false", durable = "true"),
            exchange = @Exchange(value = RabbitDefine.TOPIC_EXCHANGE, type = ExchangeTypes.TOPIC),
            key = "#.topic.#"
    ))
    public void consumer6(String message, Channel channel, @Header(AmqpHeaders.DELIVERY_TAG) long tag) throws IOException {
        log.info("消费者6(topic模式two)-队列索引:{},接收到消息:{}", tag, message);
        channel.basicAck(tag, false);
    }

    /**
     * 死信队列消息
     */
    @RabbitListener(queuesToDeclare = @Queue(RabbitDefine.DEAD_QUEUE))
    public void consumer7(String message, Channel channel, @Header(AmqpHeaders.DELIVERY_TAG) long tag) throws IOException {
        log.info("消费者7(死信队列)-队列索引:{},接收到过期消息:{}", tag, message);
        channel.basicAck(tag, false);
    }
}

6. 效果演示

  • 先启动消息提供者,初始化一下队列
  • 再启动消费者
  • 运行测试用例
    在这里插入图片描述

7. 源码分享

本项目已收录
Springboot、SpringCloud全家桶教程+源码,各种常用框架使用案例都有哦,具备完善的文档,致力于让开发者快速搭建基础环境并让应用跑起来,并提供丰富的使用示例供使用者参考,快来看看吧。

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
要下载 RabbitMQ 项目源码,可以按照以下步骤进行操作: 1. 首先,打开 RabbitMQ 官方网站,网址为 https://www.rabbitmq.com/。在网站上找到 "Downloads"(下载)菜单,点击进入。 2. 在下载页面上,你可以找到不同操作系统的 RabbitMQ 版本。根据你的操作系统选择相应的版本进行下载。例如,如果你使用的是 Windows 操作系统,可以点击下载 "Windows Installer"(Windows 安装程序)版本。 3. 下载完成后,在你电脑上找到下载的安装程序并运行它。按照安装程序的指示,逐步完成 RabbitMQ 的安装。在安装过程中,你可以选择安装 RabbitMQ 的所有组件或者只选择安装 RabbitMQ Server 组件。 4. 安装完成后,你可以找到安装目录。在默认情况下,在 Windows 上是 "C:\Program Files\RabbitMQ",在 Linux 上是 "/usr/lib/rabbitmq"。进入安装目录,你可以找到 RabbitMQ 的源代码。 5. 如果你想要获取 RabbitMQ 的源代码库,你可以使用版本控制工具 Git,克隆 RabbitMQGit 仓库到本地。打开命令行终端,切换到你想要存放源代码的目录,执行以下命令: ``` git clone https://github.com/rabbitmq/rabbitmq-server.git ``` 6. 执行完以上命令后,Git 会将 RabbitMQ 源码克隆到你的本地目录。 7. 现在你已经成功下载了 RabbitMQ 项目源码。你可以根据需要进行修改、编译和构建源码。 总结起来,下载 RabbitMQ 项目源码的步骤包括:访问 RabbitMQ 官方网站,下载适合你操作系统的版本,安装 RabbitMQ 并找到安装目录,使用 Git 克隆 RabbitMQ 源码库到本地。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

全栈小定

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值