RabbitMQ: 消息并发处理与监听器的使用

需求描述:在 Spring Boot 项目中用 MQ 处理耗时的下载任务,过程中需要停止所有 worker,等将临时文件清理后,继续后续下载任务。

1. RabbitMQ 环境

使用 docker 准备环境

version: '3'  
  
services:  
  rabbitmq:  
    image: "rabbitmq:management"  
    container_name: "rabbitmq-basic"  
    ports:  
      - "5672:5672"  
      - "15672:15672"  
    environment:  
      - TZ="Asia/Shanghai"  
      - RABBITMQ_DEFAULT_USER=${RABBITMQ_DEFAULT_USER}  
      - RABBITMQ_DEFAULT_PASS=${RABBITMQ_DEFAULT_PASS}  
    volumes:  
      - /etc/localtime:/etc/localtime:ro  
      - ./data/rabbitmq_data:/var/lib/rabbitmq  
    entrypoint: rabbitmq-server

2. 添加 Maven 依赖

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

3. 修改配置文件

application.yaml

spring:  
    rabbitmq:  
        host: "localhost"  
        port: 5672  
        username: "root"  
        password: "123456"  
        listener:  
            simple:  
                prefetch: 4  
                concurrency: 4

concurrency 指定并发数量为 4,prefetch 为消息预取的数量,如果将prefetch 设置为 1,并发的数量仍未 1。

4. 添加 RabbitMQ 配置类

本例中声明一个名为 myqueue 的队列,RabbitAdmin 用于后续获取队列的状态

import org.springframework.amqp.core.Queue;  
import org.springframework.amqp.rabbit.connection.ConnectionFactory;  
import org.springframework.amqp.rabbit.core.RabbitAdmin;  
import org.springframework.beans.factory.annotation.Autowired;  
import org.springframework.context.annotation.Bean;  
import org.springframework.context.annotation.Configuration;  
  
@Configuration  
public class MQConfig {  
    @Autowired  
    private ConnectionFactory connectionFactory;  
  
    @Bean  
    public RabbitAdmin rabbitAdmin() {  
        return new RabbitAdmin(connectionFactory);  
    }  
  
    @Bean  
    public Queue myQueue() {  
        return new Queue("myqueue");  
    }  
}

5. 创建消费者

import org.springframework.amqp.rabbit.annotation.RabbitListener;  
import org.springframework.stereotype.Component;  
  
@Component  
public class Listener {  
  
    @RabbitListener(queues = "myqueue", id = "myqueue-listener")  
    public void processMessage(String message) throws InterruptedException {  
        System.out.println("Received: " + message);  
        // 模拟耗时任务  
        Thread.sleep(10000);  
    }  
}

6. Web Controller 中添加测试方法

import org.springframework.amqp.rabbit.core.RabbitAdmin;  
import org.springframework.amqp.rabbit.core.RabbitTemplate;  
import org.springframework.amqp.rabbit.listener.RabbitListenerEndpointRegistry;  
import org.springframework.web.bind.annotation.GetMapping;  
import org.springframework.web.bind.annotation.RestController;  
  
import java.util.Properties;  
  
@RestController  
public class MQController {  
    private final RabbitTemplate rabbitTemplate;  
    private final RabbitAdmin rabbitAdmin;  
    private final RabbitListenerEndpointRegistry registry;  
  
    public MQController(RabbitTemplate rabbitTemplate, RabbitAdmin rabbitAdmin, RabbitListenerEndpointRegistry registry) {  
        this.rabbitTemplate = rabbitTemplate;  
        this.rabbitAdmin = rabbitAdmin;  
        this.registry = registry;  
    }  
  
    @GetMapping("/send")  
    public String send() {  
        for (int i = 0; i < 100; i++) {  
            rabbitTemplate.convertAndSend("myqueue", "Hello, RabbitMQ! " + i);  
        }  
        return "Message sent!";  
    }  
  
    @GetMapping("/receive")  
    public String receive() {  
        String message = (String) rabbitTemplate.receiveAndConvert("myqueue");  
        return message != null ? "Received message: " + message : "No message!";  
    }  
  
    @GetMapping("/stop")  
    public String stop() {  
        registry.getListenerContainer("myqueue-listener").stop(() ->  
                System.out.println("Listener stopped! and do something else..."));  
        return "Listener stopped!";  
    }  
  
    @GetMapping("/start")  
    public String start() {  
        registry.getListenerContainer("myqueue-listener").start();  
        return "Listener start!";  
    }  
  
    @GetMapping("/queue_status")  
    public String getQueueStatus() {  
        Properties queueInformation = rabbitAdmin.getQueueProperties("myqueue");  
        if (queueInformation != null) {  
            return "Queue Status: " + queueInformation;  
        } else {  
            return "Queue not found";  
        }  
    }  
}

接口解释:
/send: 批量发送消息
/receive: 手动处理单条消息
/stop: Listener 停止工作 ,匿名函数中传入所有 worker 停止之后需要进行的操作
/start: Listener 开始工作
/queue_status: 获取当前队列状态,返回示例:

Queue Status: {QUEUE_NAME=myqueue, QUEUE_MESSAGE_COUNT=58, QUEUE_CONSUMER_COUNT=4}
  • 8
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值