RabbitMQ 06 工作队列模式
工作队列模式结构图:

这种模式非常适合多个工人等待任务到来的场景。任务有多个,一个一个丢进消息队列,工人也有很多个,就可以将这些任务分配个各个工人,让他们各自负责一些任务,并且做的快的工人还可以多完成一些(能者多劳)。
要实现这种模式,只需要创建多个监听器即可。
先监听再发消息
这里先介绍先监听再发送消息的情况。
定义配置类。
import org.springframework.amqp.core.Binding;
import org.springframework.amqp.core.BindingBuilder;
import org.springframework.amqp.core.Exchange;
import org.springframework.amqp.core.ExchangeBuilder;
import org.springframework.amqp.core.Queue;
import org.springframework.amqp.core.QueueBuilder;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration; /**
* RabbitMQ配置类
*
* @author CodeSail
*/
@Configuration
public class RabbitMqConfig { /**
* 定义交换机,可以很多个
* @return 交换机对象
*/
@Bean("directExchange")
public Exchange exchange(){
return ExchangeBuilder.directExchange("amq.direct").build();
} /**
* 定义消息队列
* @return 消息队列对象
*/
@Bean("testQueue")
public Queue queue(){
return QueueBuilder
// 非持久化类型
.nonDurable("test_springboot")
.build();
} /**
* 定义绑定关系
* @return 绑定关系
*/
@Bean
public Binding binding(@Qualifier("directExchange") Exchange exchange,
@Qualifier("testQueue") Queue queue){
// 将定义的交换机和队列进行绑定
return BindingBuilder
// 绑定队列
.bind(queue)
// 到交换机
.to(exchange)
// 使用自定义的routingKey
.with("test_springboot_key")
// 不设置参数
.noargs();
}
}
创建两个监听器,监听同一队列。
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Component; /**
* 工作队列监听器
*
* @author 廖航
*/
@Component
public class WorkListener { @RabbitListener(queues = "test_springboot")
public void receiver1(String message) {
System.out.println("1号监听器:" + message);
} @RabbitListener(queues = "test_springboot")
public void receiver2(String message) {
System.out.println("2号监听器:" + message);
} }
定义生产者。
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;
import java.util.concurrent.TimeUnit; @SpringBootTest
class RabbitMqSpringBootTests { /**
* RabbitTemplate封装了大量的RabbitMQ操作,已经由Starter提供,因此直接注入使用即可
*/
@Autowired
private RabbitTemplate rabbitTemplate; /**
* 生产者
*/
@Test
void producer() throws InterruptedException { for (int i = 0; i < 10; i++) {
TimeUnit.SECONDS.sleep(1);
rabbitTemplate.convertAndSend("amq.direct", "test_springboot_key", "Hello World");
}
} }
启动生产者发送消息。

可以看到,当同一个队列有多个监听器时,默认采用轮询的方式消费消息。
先发消息再监听
前面介绍了先监听再发消息的情况,下面介绍先发消息再监听的情况。
向队列中发送10条消息。

启动服务消费消息。

可以看到,如果是一开始就存在消息,会被一个消费者一次性全部消费,这是因为没有对消费者的Prefetch count(预获取数量,一次性获取消息的最大数量)进行限制。
默认的Prefetch count为250。

也就是说如果希望消费者一次只拿一个消息,而不是将所有的消息全部都获取,需要设置Prefetch count。
要对这个数量进行配置,需要在配置类中定义一个自定义的ListenerContainerFactory,可以在这里设置消费者Channel的PrefetchCount的大小。
配置类中定义
ListenerContainerFactory。import org.springframework.amqp.core.Binding;
import org.springframework.amqp.core.BindingBuilder;
import org.springframework.amqp.core.Exchange;
import org.springframework.amqp.core.ExchangeBuilder;
import org.springframework.amqp.core.Queue;
import org.springframework.amqp.core.QueueBuilder;
import org.springframework.amqp.rabbit.config.SimpleRabbitListenerContainerFactory;
import org.springframework.amqp.rabbit.connection.CachingConnectionFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration; /**
* RabbitMQ配置类
*
* @author CodeSail
*/
@Configuration
public class RabbitMqConfig { @Autowired
private CachingConnectionFactory connectionFactory; ... @Bean(name = "listenerContainer")
public SimpleRabbitListenerContainerFactory listenerContainer(){
SimpleRabbitListenerContainerFactory factory = new SimpleRabbitListenerContainerFactory();
factory.setConnectionFactory(connectionFactory);
// 将PrefetchCount设定为1表示一次只能取一个
factory.setPrefetchCount(1);
return factory;
}
}
监听器中指定。
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Component; /**
* 工作队列监听器
*
* @author 廖航
*/
@Component
public class WorkListener { @RabbitListener(queues = "test_springboot", containerFactory = "listenerContainer")
public void receiver1(String message) {
System.out.println("1号监听器:" + message);
} @RabbitListener(queues = "test_springboot", containerFactory = "listenerContainer")
public void receiver2(String message) {
System.out.println("2号监听器:" + message);
} }
向队列中发送10条消息。

启动服务消费消息。

可以看到,两个监听器又实现了轮询消费消息。
Prefetch count设为了1。

至此,工作队列模式的两种情况就介绍完毕了。
- 环境
- JDK 17.0.6
- Maven 3.6.3
- SpringBoot 3.0.4
- spring-boot-starter-amqp 3.0.4
- 参考
RabbitMQ 06 工作队列模式的更多相关文章
- RabbitMQ六种队列模式-工作队列模式
前言 RabbitMQ六种队列模式-简单队列RabbitMQ六种队列模式-工作队列 [本文]RabbitMQ六种队列模式-发布订阅RabbitMQ六种队列模式-路由模式RabbitMQ六种队列模式-主 ...
- 【RabbitMQ】工作模式介绍
一.前言 之前,笔者写过< CentOS 7.2 安装 RabbitMQ> 这篇文章,今天整理一下 RabbitMQ 相关的笔记便于以后复习. 二.模式介绍 在 RabbitMQ 官网上提 ...
- RabbitMQ六种队列模式-简单队列模式
前言 RabbitMQ六种队列模式-简单队列 [本文]RabbitMQ六种队列模式-工作队列RabbitMQ六种队列模式-发布订阅RabbitMQ六种队列模式-路由模式RabbitMQ六种队列模式-主 ...
- RabbitMQ六种队列模式-发布订阅模式
前言 RabbitMQ六种队列模式-简单队列RabbitMQ六种队列模式-工作队列RabbitMQ六种队列模式-发布订阅 [本文]RabbitMQ六种队列模式-路由模式RabbitMQ六种队列模式-主 ...
- RabbitMQ六种队列模式-路由模式
前言 RabbitMQ六种队列模式-简单队列RabbitMQ六种队列模式-工作队列RabbitMQ六种队列模式-发布订阅RabbitMQ六种队列模式-路由模式 [本文]RabbitMQ六种队列模式-主 ...
- RabbitMQ六种队列模式-主题模式
前言 RabbitMQ六种队列模式-简单队列RabbitMQ六种队列模式-工作队列RabbitMQ六种队列模式-发布订阅RabbitMQ六种队列模式-路由模式RabbitMQ六种队列模式-主题模式 [ ...
- java面试一日一题:rabbitMQ的工作模式
问题:请讲下rabbitMQ的工作模式 分析:该问题纯属概念题,需要掌握rabbtiMQ的基础知识,同时该题也是切入MQ的一个引子: 回答要点: 主要从以下几点去考虑, 1.rabbitMQ的基本概念 ...
- RabbitMQ之消息模式(下)
目的: RabbitMQ之消息模式(上):https://www.cnblogs.com/huangting/p/11994539.html 消费端限流 消息的ACK与重回队列 TTL消息 死信队列 ...
- 阶段5 3.微服务项目【学成在线】_day05 消息中间件RabbitMQ_9.RabbitMQ研究-工作模式-发布订阅模式-消费者
消费者需要写两个消费者 定义邮件的类 复制以前的代码到邮件类里面进行修改 最上面 声明队列的名称和交换机的名称 监听修改为email 的队列的名称 手机短信接收端 复制一份email的接收端的代码 改 ...
- 【RabbitMQ】六种模式与SpringBoot整合
添加rabbitmq的依赖 <dependency> <groupId>org.springframework.boot</groupId> <artifac ...
随机推荐
- AFNetworking整体框架简单整理
一.AFNetworking整体框架是怎样的 1.UIKit集成模块 UIKit 2.请求序列化 Serialization 3.响应序列化 Serialization 4.会话 NSURLSessi ...
- 你不得不知道的 MySQL 优化原理
目录 MySQL逻辑架构 MySQL查询过程 客户端/服务端通信协议 查询缓存 查询优化 查询执行引擎 返回结果给客户端 总结 性能优化建议 Scheme设计与数据类型优化 创建高性能索引 索引相关的 ...
- [Python] 协程学习过程
开始 之前一直在做那个rProxy的项目,后来发现,服务端不用协程或者异步编程这样的手段是不行的,最主要的问题就是对于每个http请求都对应一个线程,这个开销非常大.对于一个网页而言,四五十个ht ...
- 为什么(++a)+(++a)=14
目录 概述 验证 反编译大法 Java 测试 概述 今天有学妹问我,下面这个代码为啥结果是14 int a=5; printf("%d\n",(++a)+(++a)); 我一看,第 ...
- 2.Canal连接MQ
1. 配置文件介绍 Canal的启动,是以创建实例(instance)的方式,每个实例都有自己单独的工作环境, 而配置也分成两个部分 canal.properties (系统根配置文件) instan ...
- 冲击900亿美元估值!邀约路演、秘密交表的Shein上市有望
双十一的狂欢刚刚结束,Shein即将赴美上市的消息又在电商圈里投下一枚重磅炸弹. 继被媒体曝光其寻求900亿美金估值后,最新的消息称其已邀请投资人参与路演,且已秘密完成交表.这个神秘的中国独角兽,离敲 ...
- Redis单线程为什么如此之快
一.概述 Redis的高并发和快简单可以归结为一下几点: 1.Redis是基于内存的: 2.Redis是单线程的: 3.Redis使用多路复用技术. 4.高效的数据结构 但具体怎么做的呢,下面来详细看 ...
- centos7 开机自动执行脚本
1.因为在centos7中/etc/rc.d/rc.local的权限被降低了,所以需要赋予其可执行权 chmod +x /etc/rc.d/rc.local 2.赋予脚本可执行权限假设/usr/loc ...
- python script 编写摘要(一)
PS:要转载请注明出处,本人版权所有. PS: 这个只是基于<我自己>的理解, 如果和你的原则及想法相冲突,请谅解,勿喷. 前置说明 本文作为本人csdn blog的主站的备份.(Bl ...
- flume采集nginx日志文件数据到Kafka
flume官网地址http://flume.apache.org/ #下载 wget https://mirrors.bfsu.edu.cn/apache/flume/1.9.0/apache-flu ...