RabbitMQ学习文档(入门篇(Demo使用SpringBoot编写))


说明:

以下Demo案例对应RabbitMQ学习文档(入门篇(Demo使用Spring编写))中的Demo代码

一、依赖

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

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

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

二、代码编写

1、Hello World!(简单队列)

1.1、RabbitMQ配置类代码
@Configuration
public class RabbitMQConfig1 {
    // 队列名称
    public static final String COMMON_QUEUE_NAME = "common_queue1";

    @Bean
    public Queue commonQueue1() {
        return QueueBuilder.durable(COMMON_QUEUE_NAME).build();
    }

}
1.2、生产者代码
@RestController
public class Provider1 {

    @Autowired
    private RabbitTemplate rabbitTemplate;

    @GetMapping("/sendMsg1")
    public String sendMsg() {
        rabbitTemplate.convertAndSend("", RabbitMQConfig1.COMMON_QUEUE_NAME, "测试消息");
        return "发送成功";
    }
}
1.3、消费者代码
@Component
public class Consumer1 {

    @RabbitListener(queues = {RabbitMQConfig1.COMMON_QUEUE_NAME})
    public void receiveMsg(Message message, Channel channel) {
        String msg = new String(message.getBody(), StandardCharsets.UTF_8);
        System.out.println("消息内容:" + msg);
    }
}

2、Work queues(工作队列 / 任务队列)

2.1、RabbitMQ配置类代码
@Configuration
public class RabbitMQConfig2 {
    // 队列名称
    public static final String COMMON_QUEUE_NAME = "common_queue2";

    @Bean
    public Queue commonQueue2() {
        return QueueBuilder.durable(COMMON_QUEUE_NAME).build();
    }

}
2.2、生产者代码
@RestController
public class Provider2 {

    @Autowired
    private RabbitTemplate rabbitTemplate;

    @GetMapping("/sendMsg2")
    public String sendMsg() {
        for (int i = 1; i <= 10; i++) {
            rabbitTemplate.convertAndSend("", RabbitMQConfig2.COMMON_QUEUE_NAME, "测试消息" + i);
        }
        return "发送成功";
    }
}
2.3、消费者代码
@Component
public class Consumer2 {

    @RabbitListener(queues = {RabbitMQConfig2.COMMON_QUEUE_NAME})
    public void receiveMsg1(Message message, Channel channel) {
        String msg = new String(message.getBody(), StandardCharsets.UTF_8);
        System.out.println("消费者1,接收到的消息内容:" + msg);
    }

    @RabbitListener(queues = {RabbitMQConfig2.COMMON_QUEUE_NAME})
    public void receiveMsg2(Message message, Channel channel) {
        String msg = new String(message.getBody(), StandardCharsets.UTF_8);
        System.out.println("消费者2,接收到的消息内容:" + msg);
    }

}

3、Work queues(工作队列 / 任务队列)

3.1、RabbitMQ配置类代码
@Configuration
public class RabbitMQConfig3 {

    // 普通交换机
    public static final String COMMON_EXCHANGE_NAME = "common_exchange3";

    // 普通队列
    public static final String COMMON_QUEUE_NAME = "common_queue3";

    @Bean
    public Exchange commonExchange3() {
        return ExchangeBuilder.fanoutExchange(COMMON_EXCHANGE_NAME).build();
    }

    @Bean
    public Queue commonQueue3() {
        return QueueBuilder.durable(COMMON_QUEUE_NAME).build();
    }

    @Bean
    public Binding commonBinding3(@Qualifier("commonQueue3") Queue commonQueue, @Qualifier("commonExchange3") Exchange commonExchange) {
        return BindingBuilder.bind(commonQueue).to(commonExchange).with("").noargs();
    }

}
3.2、生产者代码
@RestController
public class Provider3 {

    @Autowired
    private RabbitTemplate rabbitTemplate;

    @GetMapping("/sendMsg3")
    public String sendMsg() {
        rabbitTemplate.convertAndSend(RabbitMQConfig3.COMMON_EXCHANGE_NAME, "", "测试消息");
        return "发送成功";
    }
}
3.3、消费者代码
@Component
public class Consumer3 {

    @RabbitListener(queues = {RabbitMQConfig3.COMMON_QUEUE_NAME})
    public void receiveMsg(Message message, Channel channel) {
        String msg = new String(message.getBody(), StandardCharsets.UTF_8);
        System.out.println("消息内容:" + msg);
    }

}

4、Publish/Subscribe(发布订阅模式)

4.1、RabbitMQ配置类代码
@Configuration
public class RabbitMQConfig4 {

    // 普通交换机
    public static final String COMMON_EXCHANGE_NAME = "common_exchange4";

    // 普通队列1
    public static final String COMMON_QUEUE_NAME41 = "common_queue41";

    // 普通队列2
    public static final String COMMON_QUEUE_NAME42 = "common_queue42";

    // 普通队列路由1
    public static final String COMMON_ROUTING_NAME41 = "COMMON_routing41";

    // 普通队列路由2
    public static final String COMMON_ROUTING_NAME42 = "COMMON_routing42";

    // 普通队列路由3
    public static final String COMMON_ROUTING_NAME43 = "common_queue43";

    @Bean
    public Exchange commonExchange4() {
        return ExchangeBuilder.directExchange(COMMON_EXCHANGE_NAME).build();
    }

    @Bean
    public Queue commonQueue41() {
        return QueueBuilder.durable(COMMON_QUEUE_NAME41).build();
    }

    @Bean
    public Queue commonQueue42() {
        return QueueBuilder.durable(COMMON_QUEUE_NAME42).build();
    }

    @Bean
    public Binding commonBinding41(@Qualifier("commonQueue41") Queue commonQueue, @Qualifier("commonExchange4") Exchange commonExchange) {
        return BindingBuilder.bind(commonQueue).to(commonExchange).with(COMMON_ROUTING_NAME41).noargs();
    }

    @Bean
    public Binding commonBinding42(@Qualifier("commonQueue41") Queue commonQueue, @Qualifier("commonExchange4") Exchange commonExchange) {
        return BindingBuilder.bind(commonQueue).to(commonExchange).with(COMMON_ROUTING_NAME42).noargs();
    }

    @Bean
    public Binding commonBinding43(@Qualifier("commonQueue42") Queue commonQueue, @Qualifier("commonExchange4") Exchange commonExchange) {
        return BindingBuilder.bind(commonQueue).to(commonExchange).with(COMMON_ROUTING_NAME43).noargs();
    }

}
4.2、生产者代码
@RestController
public class Provider4 {

    @Autowired
    private RabbitTemplate rabbitTemplate;

    @GetMapping("/sendMsg4")
    public String sendMsg() {

        rabbitTemplate.convertAndSend(RabbitMQConfig4.COMMON_EXCHANGE_NAME, RabbitMQConfig4.COMMON_ROUTING_NAME41, "测试消息,使用路由1");
        rabbitTemplate.convertAndSend(RabbitMQConfig4.COMMON_EXCHANGE_NAME, RabbitMQConfig4.COMMON_ROUTING_NAME42, "测试消息,使用路由2");
        rabbitTemplate.convertAndSend(RabbitMQConfig4.COMMON_EXCHANGE_NAME, RabbitMQConfig4.COMMON_ROUTING_NAME43, "测试消息,使用路由3");

        return "发送成功";
    }
}
4.3、消费者代码
@Component
public class Consumer4 {

    @RabbitListener(queues = {RabbitMQConfig4.COMMON_QUEUE_NAME41})
    public void receiveMsg1(Message message, Channel channel) {
        String msg = new String(message.getBody(), StandardCharsets.UTF_8);
        System.out.println("消费者1接收到的消息内容:" + msg);
    }

    @RabbitListener(queues = {RabbitMQConfig4.COMMON_QUEUE_NAME42})
    public void receiveMsg2(Message message, Channel channel) {
        String msg = new String(message.getBody(), StandardCharsets.UTF_8);
        System.out.println("消费者2接收到的消息内容:" + msg);
    }

}

5、Routing(路由模式)

5.1、RabbitMQ配置类代码
@Configuration
public class RabbitMQConfig5 {

    // 普通交换机
    public static final String COMMON_EXCHANGE_NAME = "common_exchange5";

    // 普通队列1
    public static final String COMMON_QUEUE_NAME51 = "common_queue51";

    // 普通队列2
    public static final String COMMON_QUEUE_NAME52 = "common_queue52";

    // 普通队列路由1
    public static final String COMMON_ROUTING_NAME51 = "common.routing.51";

    // 普通队列路由2
    public static final String COMMON_ROUTING_NAME52 = "common.routing.52";

    // 普通队列路由3
    public static final String COMMON_ROUTING_NAME53 = "common.routing.53";

    // 话题1
    public static final String COMMON_TOPIC1 = "common.*.*";

    // 话题2
    public static final String COMMON_TOPIC2 = "*.*.51";

    @Bean
    public Exchange commonExchange5() {
        return ExchangeBuilder.topicExchange(COMMON_EXCHANGE_NAME).build();
    }

    @Bean
    public Queue commonQueue51() {
        return QueueBuilder.durable(COMMON_QUEUE_NAME51).build();
    }

    @Bean
    public Queue commonQueue52() {
        return QueueBuilder.durable(COMMON_QUEUE_NAME52).build();
    }

    @Bean
    public Binding commonBinding51(@Qualifier("commonQueue51") Queue commonQueue, @Qualifier("commonExchange5") Exchange commonExchange) {
        return BindingBuilder.bind(commonQueue).to(commonExchange).with(COMMON_TOPIC1).noargs();
    }

    @Bean
    public Binding commonBinding52(@Qualifier("commonQueue51") Queue commonQueue, @Qualifier("commonExchange5") Exchange commonExchange) {
        return BindingBuilder.bind(commonQueue).to(commonExchange).with(COMMON_TOPIC2).noargs();
    }

    @Bean
    public Binding commonBinding53(@Qualifier("commonQueue52") Queue commonQueue, @Qualifier("commonExchange5") Exchange commonExchange) {
        return BindingBuilder.bind(commonQueue).to(commonExchange).with(COMMON_TOPIC2).noargs();
    }

}
5.2、生产者代码
@RestController
public class Provider5 {

    @Autowired
    private RabbitTemplate rabbitTemplate;

    @GetMapping("/sendMsg5")
    public String sendMsg() {

        rabbitTemplate.convertAndSend(RabbitMQConfig5.COMMON_EXCHANGE_NAME, RabbitMQConfig5.COMMON_ROUTING_NAME51, "测试消息,使用路由1");
        rabbitTemplate.convertAndSend(RabbitMQConfig5.COMMON_EXCHANGE_NAME, RabbitMQConfig5.COMMON_ROUTING_NAME52, "测试消息,使用路由2");
        rabbitTemplate.convertAndSend(RabbitMQConfig5.COMMON_EXCHANGE_NAME, RabbitMQConfig5.COMMON_ROUTING_NAME53, "测试消息,使用路由3");

        return "发送成功";
    }
}
5.3、消费者代码
@Component
public class Consumer5 {

    @RabbitListener(queues = {RabbitMQConfig5.COMMON_QUEUE_NAME51})
    public void receiveMsg1(Message message, Channel channel) {
        String msg = new String(message.getBody(), StandardCharsets.UTF_8);
        System.out.println("消费者1接收到的消息内容:" + msg);
    }

    @RabbitListener(queues = {RabbitMQConfig5.COMMON_QUEUE_NAME52})
    public void receiveMsg2(Message message, Channel channel) {
        String msg = new String(message.getBody(), StandardCharsets.UTF_8);
        System.out.println("消费者2接收到的消息内容:" + msg);
    }

}

三、难点解读

1、生产者发送消息持久化怎么设置?

不用设置,通过rabbitTemplate.convertAndSend()方式发送的消息默认就是持久化的。

解释:

大家都知道,在spring整合RabbtitMQ的时候,我们通过如下方式来设置发送消息持久化:

// 参数3:设置消息持久化(即使队列重启消息也依然存在)
channel.basicPublish("", QUEUE_NAME, MessageProperties.PERSISTENT_TEXT_PLAIN, message.getBytes(StandardCharsets.UTF_8));

我们看一下究竟是那个参数来设置持久化的,我们查看MessageProperties.PERSISTENT_TEXT_PLAIN的详情,可以看到deliveryMode值为2代表消息持久化,如下:

在这里插入图片描述

但是从上面的springboot整合RabbitMQ的Demo可以看到,我们并没有去设置消息持久化,但是我想说默认情况下消息已经持久化了,下面我们来一探究竟

既然我们只使用了下面这种发送方式:

rabbitTemplate.convertAndSend("", RabbitMQConfig1.COMMON_QUEUE_NAME, "测试消息");

我们一步步点进去看下:

org.springframework.amqp.rabbit.core.RabbitTemplate#convertAndSend(java.lang.String, java.lang.String, java.lang.Object)

org.springframework.amqp.rabbit.core.RabbitTemplate#convertAndSend(java.lang.String, java.lang.String, java.lang.Object, org.springframework.amqp.rabbit.connection.CorrelationData)

org.springframework.amqp.rabbit.core.RabbitTemplate#send(java.lang.String, java.lang.String, org.springframework.amqp.core.Message, org.springframework.amqp.rabbit.connection.CorrelationData)

org.springframework.amqp.rabbit.core.RabbitTemplate#doSend

org.springframework.amqp.rabbit.core.RabbitTemplate#sendToRabbit

现在把sendToRabbit方法的详细内容贴在下面,如下:

在这里插入图片描述

上图用红框圈起来的就是发送参数,也就是配置消息持久化的地方,我们看下下面代码的内部作用:

BasicProperties convertedMessageProperties = this.messagePropertiesConverter
				.fromMessageProperties(message.getMessageProperties(), this.encoding);

这是一个接口,但是只有一个实现类,我们直接进入实现类,可以看到里面有设置deliveryMode的地方,如下:

在这里插入图片描述
既然deliveryMode的值来自于source.getDeliveryMode()方法,我们跟进去最终能看到如下位置,该值就是设置消息持久化的,所以我说消息默认就是持久化,证明如下:

在这里插入图片描述

2、交换机持久化、不自动删除参数如何设置?

不用设置,通过ExchangeBuilder.topicExchange(交换机名称).build()方式声明的交换机默认就是持久化、不自动删除的。

解释:

在spring整合RabbitMQ中,我们设置交换机不持久化、不自动删除参数的方式如下:

// 参数说明
// 参数1:交换机名称
// 参数2:交换机类型
// 参数3:交换机是否持久化
// 参数4:交换机是否自动删除
// 参数5:交换机参数
channel.exchangeDeclare(EXCHANGE_NAME, BuiltinExchangeType.DIRECT, true, false, null);

在springboot整合RabbitMQ中,既然我们使用如下方式声明交换机,如下:

@Bean
public Exchange commonExchange5() {
    return ExchangeBuilder.topicExchange(COMMON_EXCHANGE_NAME).build();
}

那我们就把给大家看一下生成结果:

在这里插入图片描述

3、队列持久化、不独占、不自动删除参数如何设置?

不用设置,通过QueueBuilder.durable(队列名称).build()方式声明的队列默认就是持久化、不独占、不自动删除的。

解释:

在spring整合RabbitMQ中,我们设置队列持久化、不独占、不自动删除参数的方式如下:

/**
 * 创建普通队列
 * 注意:我们也在这里声明了队列,因为我们可能在发布者之前启动消费者,所以我们要确保队列存在,然后再尝试从中消费消息
 * 参数1:队列名称
 * 参数2:是否持久化
 *          队列持久化之后,即使RabbitMQ重启,队列依然存在
 * 参数3:是否排他
 *          设置排他:仅限当前连接使用,虽然我不太懂,但是不要设置,毕竟其他连接也要使用
 * 参数4:自动删除
 *          没有消费者连接是否自动删除
 * 参数5:附加参数
 *          比如可以设置死信队列等
 */
channel.queueDeclare(队列名称, true, false, false, 附加参数);

在springboot整合RabbitMQ中,既然我们使用如下方式声明队列,如下:

@Bean
public Queue commonQueue1() {
    // 默认情况下,创建持久化、不排它、不自动删除的队列
    return QueueBuilder.durable(COMMON_QUEUE_NAME).build();
}

那我们就把给大家看一下生成结果:

在这里插入图片描述

4、消费者—能者多劳如何实现?

在配置文件application.properties中添加参数即可:

# channel中最多一条消息,符合能者多劳原则
spring.rabbitmq.listener.simple.prefetch=1

5、消费者—手动确认消费消息,如何实现?

在默认情况下,消息是自动确定消费的,下面说明如何手动确定消息消费。

方式1(不推荐;原因是这种方式必须手动确认消息消费,遗忘就会导致消息不能被确认消费,容易产生问题):

第1步:

在配置文件application.properties中添加参数:

spring.rabbitmq.listener.direct.acknowledge-mode=manual

第2步:

在消费消息之后,必须手动确定消息消费:

// 参数说明
// 参数1:消息标识
// 参数2:是否批量确定消息被消费;原因是channel中这一批次消息中可能存在多个消息,设置成false代表只手动确定当前消息被消费
channel.basicAck(message.getMessageProperties().getDeliveryTag(), false);

详细代码截图如下:

在这里插入图片描述

方式2(推荐;原因是被设置的地方才需要手动ack,其他地方还是自动ack):

说明:不需要像上面一样修改配置文件,只是需要在@RabbitListener中设置属性ackMode = "MANUAL"即可

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 明快de玄米61
 * @date 2022/4/22 23:14
 */
@Component
public class Consumer8 {

    // 下面添加了一个ackMode 属性,并且配置为MANUAL,代表需要手动确定消息消费,相当于spring整合RabbitMQ时消费者中的channel.basicConsume()方法第2个参数设置为false,代表手动确认消息消费
    @RabbitListener(queues = {RabbitMQConfig8.QUEUE_NAME}, ackMode = "MANUAL")
    public void receiveMsg1(Message message, Channel channel, Student student) throws IOException {
	    // 打印消息
        System.out.println("消费者接收到的消息内容:" + student.toString());

        // 手动确认消息
        channel.basicAck(message.getMessageProperties().getDeliveryTag(), false);
    }

}

6、application.properties配置文件中如何配置RabbitMQ连接信息

6.1、主机、端口配置方式(RabbitMQ单机)
spring.rabbitmq.host=localhost
spring.rabbitmq.port=5672
spring.rabbitmq.username=admin
spring.rabbitmq.password=secret
6.2、地址属性配置方式(RabbitMQ单机)
# 参数解读
# 用户名:admin
# 密码:secret
# ip:localhost
# 端口:5672
spring.rabbitmq.addresses=amqp://admin:secret@localhost:5672
6.3、地址属性配置方式(RabbitMQ集群)
# 参数解读
# 用户名:admin
# 密码:secret
# ip:192.168.1.22, 192.168.1.8, 192.168.1.144
# 端口:5672
spring:
  rabbitmq:
    addresses: 192.168.1.22:5672,192.168.1.8:5672,192.168.1.144:5672
    username: admin
    password: guest

拓展: 在spring官网提到,如果配置了addresses方式,那么host和port配置将被忽略,截图如下:

在这里插入图片描述

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Spring Boot集成RabbitMQ可以通过以下步骤完成: 1. 添加Maven依赖:在pom.xml文件中添加RabbitMQSpring Boot Starter依赖。 ```xml <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-amqp</artifactId> </dependency> ``` 2. 配置RabbitMQ连接信息:在application.properties(或application.yml)文件中配置RabbitMQ的连接信息。 ```properties spring.rabbitmq.host=your_rabbitmq_host spring.rabbitmq.port=your_rabbitmq_port spring.rabbitmq.username=your_rabbitmq_username spring.rabbitmq.password=your_rabbitmq_password ``` 3. 创建RabbitMQ发送者:创建一个发送消息的类,使用`RabbitTemplate`发送消息到指定的交换机和队列。 ```java import org.springframework.amqp.core.RabbitTemplate; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; @Component public class RabbitMQSender { @Autowired private RabbitTemplate rabbitTemplate; public void sendMessage(String exchange, String routingKey, Object message) { rabbitTemplate.convertAndSend(exchange, routingKey, message); } } ``` 4. 创建RabbitMQ接收者:创建一个接收消息的类,使用`@RabbitListener`注解监听指定的队列,处理接收到的消息。 ```java import org.springframework.amqp.rabbit.annotation.RabbitListener; import org.springframework.stereotype.Component; @Component public class RabbitMQReceiver { @RabbitListener(queues = "your_queue_name") public void receiveMessage(Object message) { // 处理接收到的消息 System.out.println("Received message: " + message.toString()); } } ``` 5. 发送和接收消息:在需要发送或接收消息的地方调用对应的方法。 ```java @Autowired private RabbitMQSender rabbitMQSender; public void sendMessage() { rabbitMQSender.sendMessage("your_exchange_name", "your_routing_key", "Hello, RabbitMQ!"); } ``` 以上是基本的使用方式,你可以根据实际需求进行扩展和配置。注意,你还需要安装并启动RabbitMQ服务。 希望对你有所帮助!如果有任何疑问,请随时提问。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值