SpringBoot整个RabbitMQ详细~

搭建环境

1、安装RabbitMQ,我是用的是Docker方式安装的,大家根据个人习惯自行安装哈

docker run -d -p 5672:5672 -p 15672:15672 --name rabbitmq -e RABBITMQ_DEFAULT_USER=qbb -e RABBITMQ_DEFAULT_PASS=qbb rabbitmq:3.8-management

SpringBoot整合RabbitMQ

Producer生产者端代码

1、创建一个maven工程

image

2、导入相关的依赖

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.qbb</groupId>
    <artifactId>springboot-rabbitmq</artifactId>
    <version>1.0-SNAPSHOT</version>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.6.7</version>
    </parent>

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

3、编写application.yml配置文件

server:
  port: 9001
spring:
  application:
    name: springboot-rabbitmq
  rabbitmq:
    host: # 你MQ的地址
    port: 5672
    username: admin
    password: admin
    virtual-host: /

4、主启动类

package com.qbb.rabbitmq;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

/**
 * @author QiuQiu&LL (个人博客:https://www.cnblogs.com/qbbit)
 * @version 1.0
 * @date 2022-07-28  21:33
 * @Description:
 */
@SpringBootApplication
public class SpringBootRabbitMQ {
    public static void main(String[] args) {
        SpringApplication.run(SpringBootRabbitMQ.class, args);
    }
}

5、业务逻辑

(1)我们创建一个RabbitMQConfig的配置类,帮助我们来创建交换机、队列以及绑定关系

package com.qbb.rabbitmq.config;

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

/**
 * @author QiuQiu&LL (个人博客:https://www.cnblogs.com/qbbit)
 * @version 1.0
 * @date 2022-07-28  21:34
 * @Description:
 */
@Configuration
public class RabbitMQConfig {

    /**
     * 交换机名称
     */
    public static final String TOPIC_EXCHANGE_NAME = "qiu_topic_exchange";

    /**
     * 队列名称
     */
    public static final String QUEUE_NAME = "qiu_queue";

    /**
     * 创建交换机
     *
     * @return
     */
    @Bean("qiuExchange")
    public Exchange createExchange() {
        return ExchangeBuilder.topicExchange(TOPIC_EXCHANGE_NAME).durable(true).build();
    }

    /**
     * 创建队列
     *
     * @return
     */
    @Bean("qiuQueue")
    public Queue createQueue() {
        return QueueBuilder.durable(QUEUE_NAME).build();
    }

    /**
     * 绑定交换机和队列
     *
     * @param qiuExchange
     * @param qiuQueue
     * @return
     */
    @Bean
    public Binding binding(@Qualifier("qiuExchange") Exchange qiuExchange, @Qualifier("qiuQueue") Queue qiuQueue) {
        return BindingBuilder.bind(qiuQueue).to(qiuExchange).with("qiu.#").noargs();
    }
}

(2)编写Producer发送消息的测试代码

package com.qbb.rabbitmq;

import com.qbb.rabbitmq.config.RabbitMQConfig;
import org.junit.jupiter.api.Test;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

/**
 * @author QiuQiu&LL (个人博客:https://www.cnblogs.com/qbbit)
 * @version 1.0
 * @date 2022-07-28  21:56
 * @Description:
 */
@SpringBootTest
public class ProducerTest {

    @Autowired
    private RabbitTemplate rabbitTemplate;

    @Test
    public void testSendMsg(){
        rabbitTemplate.convertAndSend(RabbitMQConfig.TOPIC_EXCHANGE_NAME,
                "qiu.haha", "等我完成目标就来找你~");
    }
}

image

image

Consumer消费者端代码

1、创建一个maven工程

image

2、导入相关的依赖

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.qbb</groupId>
    <artifactId>springboot-rabbitmq-consumer</artifactId>
    <version>1.0-SNAPSHOT</version>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.6.7</version>
    </parent>

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

3、编写application.yml配置文件

server:
  port: 9002
spring:
  application:
    name: springboot-rabbitmq
  rabbitmq:
    host: 
    port: 5672
    username: admin
    password: admin
    virtual-host: /

4、主启动类

package com.qbb.rabbitmq;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

/**
 * @author QiuQiu&LL (个人博客:https://www.cnblogs.com/qbbit)
 * @version 1.0
 * @date 2022-07-28  22:09
 * @Description:
 */
@SpringBootApplication
public class SpringBootRabbitMQConsumer {
    public static void main(String[] args) {
        SpringApplication.run(SpringBootRabbitMQConsumer.class, args);
    }
}

5、业务逻辑

(1)创建一个MQListener监听器,用于监听队列消费消息

package com.qbb.rabbitmq.listener;

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

/**
 * @author QiuQiu&LL (个人博客:https://www.cnblogs.com/qbbit)
 * @version 1.0
 * @date 2022-07-28  22:10
 * @Description:
 */
@Component
public class RabbitMQListener {

    /**
     * 监听队列
     *
     * @param message
     */
    @RabbitListener(queues = "qiu_queue")
    public void msgConsumer(Message message) {
        System.out.println("message = " + message);
    }
}

(2)启动主程序测试一下

image

RabbitMQ高级特性

image

1、消息可靠性投递confirm确认模式和return回退模式

  • 修改yml配置文件
spring:
  application:
    name: springboot-rabbitmq
  rabbitmq:
    host: 
    port: 5672
    username: admin
    password: admin
    virtual-host: /
    # 是否触发回调方法
    # NONE值是禁用发布确认模式,是默认值
    # CORRELATED值是发布消息成功到交换器后会触发回调方法
    # SIMPLE值经测试有两种效果:
    #     其一效果和CORRELATED值一样会触发回调方法
    #     其二在发布消息成功后使用rabbitTemplate
    #       调用waitForConfirms或waitForConfirmsOrDie方法等待broker节点返回发送结果,根据返回结果来判定下一步的逻辑,
    #       要注意的点是waitForConfirmsOrDie方法如果返回false则会关闭channel,则接下来无法发送消息到broker;
    publisher-confirm-type: correlated
    publisher-returns: true
    listener:
      simple:
        # 开启手动确定
        acknowledge-mode: manual
  • 编写测试代码
package com.qbb.rabbitmq;

import com.qbb.rabbitmq.config.RabbitMQConfig;
import org.junit.jupiter.api.Test;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.connection.CorrelationData;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

/**
 * @author QiuQiu&LL (个人博客:https://www.cnblogs.com/qbbit)
 * @version 1.0
 * @date 2022-07-28  21:56
 * @Description:
 */
@SpringBootTest
public class ProducerTest {

    @Autowired
    private RabbitTemplate rabbitTemplate;

    @Test
    public void testSendMsg(){
        /**
         * false:RabbitMQ会把消息直接丢弃
         * true:RabbitMQ会调用Basic.Return命令将消息返回给生产者
         */
        rabbitTemplate.setMandatory(true);

        //设置ReturnsCallback
        rabbitTemplate.setReturnsCallback( returnedMessage -> {
            //消息对象
            Message message = returnedMessage.getMessage();
            //错误码
            int replyCode = returnedMessage.getReplyCode();
            //错误信息
            String replyText = returnedMessage.getReplyText();
            //交换机
            String exchange = returnedMessage.getExchange();
            //路由key
            String routingKey = returnedMessage.getRoutingKey();

            System.out.println("消息从交换机到队列失败,详细信息如下:");
            System.out.println("消息对象:"+message);
            System.out.println("错误码:"+replyCode);
            System.out.println("错误信息:"+replyText);
            System.out.println("交换机:"+exchange);
            System.out.println("路由key:"+routingKey);
        });

        //设置ConfirmCallback
        rabbitTemplate.setConfirmCallback(new RabbitTemplate.ConfirmCallback() {
            /**
             * @param correlationData 相关配置信息
             * @param ack 交换机是否成功收到消息
             * @param cause 错误信息
             */
            @Override
            public void confirm(CorrelationData correlationData, boolean ack, String cause) {
                if (ack){
                    System.out.println("成功发送消息到交换机");
                }else {
                    System.out.println("消息发送到交换机失败");
                    System.out.println("失败原因:"+cause);
                }
            }
        });
        // 错误的示例,大家自行修改
        rabbitTemplate.convertAndSend(RabbitMQConfig.TOPIC_EXCHANGE_NAME,
                "qiu.haha", "等我完成目标就来找你~");
    }
}

2、Consumer端手动ACK

RabbitMQ提供了三种确认方式:

  • 自动确认:acknowledge="none"
  • 手动确认:acknowledge="manual"
  • 根据异常情况确认:acknowledge="auto" (不推荐)

修改配置文件

 listener:
      type: simple
      simple:
        #采用手动应答
        acknowledge-mode: manual
        prefetch: 1 #限制每次发送一条数据。

添加一个ACKListener监听器

package com.qbb.rabbitmq.listener;

import com.rabbitmq.client.Channel;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Component;

import java.io.IOException;

/**
 * @author QiuQiu&LL (个人博客:https://www.cnblogs.com/qbbit)
 * @version 1.0
 * @date 2022-07-29  21:32
 * @Description:
 */

@Component
public class AckListener {

    @RabbitListener(queues = {"akc-queue"})
    public void testQueue(Message message, Channel channel) throws IOException {
        System.out.println("ack-queue消费:" + new String(message.getBody()));
        /*
              listener:
                type: simple
                simple:
                  #采用手动应答
                  acknowledge-mode: manual
                  prefetch: 1 #限制每次发送一条数据。
         */
//        采用手动ack,一条条的消费
        channel.basicAck(message.getMessageProperties().getDeliveryTag(), false);

        /**
         * 参数一:DeliveryTag
         * 参数二:是否接收多个消息
         * 参数三:是否重回队列,如果为true消息会重新回到queue, broker会重新发送该消息给消费端
         */
        //channel.basicNack(message.getMessageProperties().getDeliveryTag(),true,true);
    }
} 

测试
image

3、Consumer端限流

修改配置文件

#采用手动应答
acknowledge-mode: manual
prefetch: 1 #限制每次消费N条数据。

4、TTL

  • 设置队列的过期时间
    • x-message-ttl,单位:ms(毫秒),这样的话进入队列的所有消息都遵循这个过期时间。
  • 设置单个消息的过期时间(expiretion)
    • expiration,单位:ms(毫秒),这样的话只有这条消息有过期时间。这里的消息过期了,如果这条消息是在头部,才会丢弃

5、死信队列

  • 消息成为死信的三种情况
    • 消息超过了队列的最大长度(max-length)
    • Consumer端basicNAck|basicReject,消费端拒收,并且requeue=false不重新入队
    • 消息过期

6、延迟队列(RabbitMQ没有这个实现)

  • 但是我们可以通过TTL+死信队列解决
    image

7、日志与监控

http://ip:15672/直接访问web图形化界面,用命令也可以查看,但是个人感觉没有图形化界面友好!!!

8、保证消息的幂等性

  • 使用乐观锁的方式解决
posted @   我也有梦想呀  阅读(57)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· Docker 太简单,K8s 太复杂?w7panel 让容器管理更轻松!
点击右上角即可分享
微信分享提示