不确定我是否只是密集,但我正在尝试配置spring(没有XML配置)来连接RabbitMQ。我可以通过创建一个SmartMessageListenerContainer来使用来自我的队列的消息来使其正常工作,但我磕磕绊绊的是如何创建一组容器来侦听同一队列。我的理解是你得到一个容器,每个队列有一个消息监听器,但你可以配置多个容器来监听同一个队列。我的目标是实现RabbitMQ docs概述的工作队列策略(一个队列,多个工作者)。
我试图实现的是每个消息传递(prefetch = 1)的一个消息监听器/工作器以及绑定到单个队列的消息容器池,以有效地创建我的工作池。最终,这一切都需要是动态的,因为我的服务的每个实例都需要适当调整到预期的工作量。有些情况可能只需要几个工人,而其他人可能需要很多工人。这就是为什么为每个容器声明一个bean在我的情况下并不真正起作用,因为我不知道我需要多少钱。另外,做一些类似的东西似乎很时髦(这就是我见过的大多数例子):
@Bean
SimpleMessageListenerContainer container1() {...}
@Bean
SimpleMessageListenerContainer container2() {...}
@Bean
SimpleMessageListenerContainer container3() {...}
下面是我当前的代码,我注册了一个返回容器集合的bean。这个方法自动被调用并按预期创建所有容器,但容器似乎永远不会自动启动(我很清楚我明白为什么因为我手动创建容器)。我试图在创建后手动调用每个容器上的start()方法,但是当达到这一小段代码时,每个容器有60秒的延迟:
AsyncMessageProcessingConsumer
private FatalListenerStartupException getStartupException() throws TimeoutException, InterruptedException {
this.start.await(60000L, TimeUnit.MILLISECONDS);
return this.startupException;
}
但我确实看到一篇提到需要实现SmartLifeCycle接口的帖子。我当然可以在下面的配置类中执行此操作,然后在调用start()方法时调用我创建的每个容器上的start()方法。这是我唯一的选择,还是我在这里完全遗漏了什么?
我的兔子配置类:
@Configuration
public class RabbitConfiguration {
private final List<SimpleMessageListenerContainer> listenerContainers;
private final boolean useDurableQueues;
private final String exchangeName;
private final String inboundQueueName;
private final String outboundQueueName;
private final String host;
private final String virtualHost;
private final String userName;
private final String password;
private final int maxWorkers;
public RabbitConfiguration(
@Value( "${com.unwiredrev.remotelink.rabbitmq.exchangeName}" )
final String exchangeName,
@Value( "${com.unwiredrev.remotelink.rabbitmq.inboundQueueName}" )
final String inboundQueueName,
@Value( "${com.unwiredrev.remotelink.rabbitmq.outboundQueueName}" )
final String outboundQueueName,
@Value( "${com.unwiredrev.remotelink.rabbitmq.priorityQueueName}" )
final String priorityQueueName,
@Value( "${com.unwiredrev.remotelink.rabbitmq.username}" )
final String userName,
@Value( "${com.unwiredrev.remotelink.rabbitmq.password}" )
final String password,
@Value( "${com.unwiredrev.remotelink.rabbitmq.host}" )
final String host,
@Value( "${com.unwiredrev.remotelink.rabbitmq.virtualHost}" )
final String virtualHost,
@Value( "${com.unwiredrev.remotelink.rabbitmq.useDurableQueues:true}" )
final boolean useDurableQueues,
@Value( "${com.unwiredrev.remotelink.rabbitmq.maxWorkers:1}")
final int maxWorkers ) {
this.exchangeName = exchangeName;
this.inboundQueueName = inboundQueueName;
this.outboundQueueName = outboundQueueName;
this.useDurableQueues = useDurableQueues;
this.host = host;
this.virtualHost = virtualHost;
this.userName = userName;
this.password = password;
this.maxWorkers = maxWorkers;
this.listenerContainers = new ArrayList<>( maxWorkers );
}
public String getExchangeName() {
return exchangeName;
}
public String getInboundQueueName() {
return inboundQueueName;
}
public String getOutboundQueueName() {
return outboundQueueName;
}
public boolean useDurableQueues() {
return useDurableQueues;
}
public String getHost() {
return host;
}
public Optional<String> getVirtualHost() {
return Optional.ofNullable( StringUtils.trimToNull( this.virtualHost ) );
}
public String getUserName() {
return userName;
}
public String getPassword() {
return password;
}
public int getMaxWorkers() {
return maxWorkers;
}
@Bean
Collection<SimpleMessageListenerContainer> messageListenerContainers( @NotNull ConnectionFactory connectionFactory, @NotNull RabbitAdmin rabbitAdmin ) {
IntStream.range( 0, getMaxWorkers() ).forEach( idx -> {
final SimpleMessageListenerContainer container = new SimpleMessageListenerContainer();
container.setQueueNames( inboundQueueName );
container.setConnectionFactory( connectionFactory );
container.setMessageListener( new MessageReceiver() );
container.setAcknowledgeMode( AcknowledgeMode.MANUAL );
container.setRabbitAdmin( rabbitAdmin );
listenerContainers.add( container );
} );
return listenerContainers;
}
@Bean
RabbitAdmin rabbitAdmin( @NotNull ConnectionFactory connectionFactory ) {
return new RabbitAdmin( connectionFactory );
}
@Bean
ConnectionFactory connectionFactory() {
final CachingConnectionFactory connectionFactory = new CachingConnectionFactory( getHost() );
connectionFactory.setUsername( getUserName() );
connectionFactory.setPassword( getPassword() );
getVirtualHost().ifPresent( connectionFactory::setVirtualHost );
return connectionFactory;
}
@Bean( name = "rlClientExchange")
TopicExchange getExchange() {
return new TopicExchange( getExchangeName(), true, false );
}
@Bean( name = "rlClientInboundQueue" )
Queue inboundQueue() {
return new Queue( getInboundQueueName(), useDurableQueues() );
}
@Bean
Queue outboundQueue() {
return new Queue( getOutboundQueueName(), useDurableQueues() );
}
@Bean
Binding inboundQueueBinding( @NotNull final TopicExchange exchange ) {
if( exchange == null ) {
throw new IllegalArgumentException( "Rabbit topic exchange cannot be null." );
}
return BindingBuilder.bind( inboundQueue() )
.to( exchange )
.with( getInboundQueueName() );
}
@Bean
Binding outboundQueueBinding( @NotNull final TopicExchange exchange ) {
if( exchange == null ) {
throw new IllegalArgumentException( "Rabbit topic exchange cannot be null." );
}
return BindingBuilder.bind( outboundQueue() )
.to( exchange )
.with( getOutboundQueueName() );
}
}