序言:
当数据通过生产者产生到发送到exchange交换器,再通过设定的路由规则,经过routingKey,最终会落地到queue 中。这个时候引出了Listener消费者了。在第一章中有对RabbitAnnotationDrivenConfiguration该类中源码做过基本分析,该类最大的作用就是通过配置文件的设定用于构建RabbitListenerContainerFactory(该接口的实现,工厂设计模式用以创建核心的MessageListenerContainer
容器类,而该类MessageListenerContainer用以管理MessageListener,最终实现的该接口类操作Connection最终来消费数据)
对于spring提供了两种工厂实现,SimpleRabbitListenerContainerFactory与DirectRabbitListenerContainerFactoryConfigurer,
1:SimpleRabbitListenerContainerFactory(SMLC)
用于构建SimpleMessageListenerContainer
在章节一中也描述了该模式下,rabbitmq的消费模式,该监听容器通过客户端多线程来并行的处理消息,通过上述的配置设置并行度。也可以监控多个队列并在运行时对队列进行增删
。系统通过 concurrentConsumers、maxConcurrentConsumers 灵活设定当前容器中消费者的数量,不论监控多少个队列,channel与当前线程都会一一对应(这也是为何命令为Simple的因素),即使用同一consumer线程来会处理所有的队列。即这里我们先使用该模式来进行消费。
1.1:通过Factory构建SimpleMessageListenerContainer
当设置完成,我们如果在应用中创建SimpleMessageListenerContainer,来监听queue呢。spring也提供了两种方式
yml配置:
listener:
type: simple
simple:
##这里使用none后续对此进行详细描述
acknowledge-mode: none
auto-startup: true
##设置消费并行度
concurrency: 2
##设置最大并行度
max-concurrency: 2
##设置一个批次最大拉取数量
batch-size: 3
##不开启重试 避免重复消费
retry:
enabled: false
## 每个消费者可能未完成的未确认消息的最大数量
#prefetch:
## 若容器中声明的的queue不存在了(queue在代理上不可用或在运行时被删除了) 是否需要停止对应容器默认true
missing-queues-fatal: true
## 默认情况下,拒绝交付是否重新排队
default-requeue-rejected: true
# 应该多久发布一次空闲容器事件 可用于监控
idle-event-interval: 10000
1.1.1: MessageListener
单条消费,可以通过配置开启自动ack或不开启ack
@Autowired
private SimpleRabbitListenerContainerFactory simpleRabbitListenerContainerFactory;
//单条消费
@Bean
public MessageListenerContainer simpleMessageListenerContainer(){
SimpleMessageListenerContainer listenerContainer = simpleRabbitListenerContainerFactory.createListenerContainer();
//设置被监控的queue
listenerContainer.setQueueNames(CommonConstant.queue_direct1,CommonConstant.queue_direct2);
//等待消息到达超时时间默认1s
listenerContainer.setReceiveTimeout(1000);
//手动确认
listenerContainer.setAcknowledgeMode(AcknowledgeMode.NONE);
//默认10s
listenerContainer.setStartConsumerMinInterval(10*1000);
//默认60s
listenerContainer.setStopConsumerMinInterval(60*1000);
//设置消费者唯一标记 基于queue设置
listenerContainer.setConsumerTagStrategy(queue -> {
return queue+"_"+ UUID.randomUUID().toString();
});
listenerContainer.setMessageListener(message->{
//获取数据
byte[] body = message.getBody();
String str = new String(body);
Thread thread=Thread.currentThread();
log.info("message:{} ThreadId is:{} ConsumerTag:{} Queue:{}"
,str,thread.getId(),message.getMessageProperties().getConsumerTag(),message.getMessageProperties().getConsumerQueue());
});
return listenerContainer;
}
上述设置了2个并行情况,有两个线程(consumer)并行消费
1.1.2: ChannelAwareMessageListener
包含channel与message可以进行手动ack确定
@Autowired
private SimpleRabbitListenerContainerFactory simpleRabbitListenerContainerFactory;
@Bean
public MessageListenerContainer simpleChannelMessageListenerContainer(){
SimpleMessageListenerContainer listenerContainer = simpleRabbitListenerContainerFactory.createListenerContainer();
//设置被监控的queue
listenerContainer.setQueueNames(CommonConstant.queue_direct1,CommonConstant.queue_direct2);
//等待消息到达超时时间默认1s
listenerContainer.setReceiveTimeout(1000);
//手动确认
listenerContainer.setAcknowledgeMode(AcknowledgeMode.MANUAL);
//默认10s
listen