我有一个Java Spring Boot 1.5.10应用程序,我将连接到两个不同的RabbitMQ服务器。一个RabbitMQ服务器与Spring Boot应用程序在同一主机上运行,另一个在另一个/远程主机上运行。 这个版本的Spring Boot包括org.springframework.amqp:spring-amqp:jar:1.7.6.RELEASE,顺便说一下。所以,这里有一些与本地RabbitMQ服务器有关的配置代码:
@Bean
public ConnectionFactory rabbitConnectionFactory() {
CachingConnectionFactory factory = new CachingConnectionFactory(host);
factory.setVirtualHost(vhost);
factory.setUsername(username);
factory.setPassword(password);
factory.setChannelCacheSize(2);
// Add a custom client connection property, which will show up in the Admin UI (useful for troubleshooting).
factory.getRabbitConnectionFactory().getClientProperties().put("Connection Type", "Local");
return factory;
}
@Bean
public RabbitTemplate rabbitTemplate(ConnectionFactory rabbitConnectionFactory,
MessageConverter jackson2JsonMessageConverter) {
RabbitTemplate rabbitTemplate = new RabbitTemplate(rabbitConnectionFactory);
rabbitTemplate.setMessageConverter(jackson2JsonMessageConverter);
return rabbitTemplate;
}
@Bean
public SimpleRabbitListenerContainerFactory rabbitListenerContainerFactory(ConnectionFactory rabbitConnectionFactory) {
SimpleRabbitListenerContainerFactory factory = new SimpleRabbitListenerContainerFactory();
factory.setConnectionFactory(rabbitConnectionFactory);
return factory;
}
@Bean
public RabbitAdmin admin(ConnectionFactory rabbitConnectionFactory) {
RabbitAdmin rabbitAdmin = new RabbitAdmin(rabbitConnectionFactory);
rabbitAdmin.afterPropertiesSet();
rabbitAdmin.setAutoStartup(false);
return rabbitAdmin;
}
以下是我在另一台主机上远程运行的RabbitMQ服务器的一些配置代码:
@Bean
public ConnectionFactory remoteConnectionFactory() {
CachingConnectionFactory factory = new CachingConnectionFactory(remoteHost);
factory.setVirtualHost(remoteVhost);
factory.setUsername(remoteUsername);
factory.setPassword(remotePassword);
// By default, only one Channel will be cached, with further requested Channels being created and disposed on demand.
// Consider raising the "channelCacheSize" value in case of a high-concurrency environment.
factory.setChannelCacheSize(3);
factory.setConnectionThreadFactory(new CustomizableThreadFactory("RemoteRabbit-"));
// Add a custom client connection property, which will show up in the Admin UI (useful for troubleshooting).
factory.getRabbitConnectionFactory().getClientProperties().put("Connection Type", "Remote");
return factory;
}
@Bean
public RabbitAdmin remoteAdmin(ConnectionFactory remoteConnectionFactory) {
RabbitAdmin rabbitAdmin = new RabbitAdmin(remoteConnectionFactory);
rabbitAdmin.setIgnoreDeclarationExceptions(true);
return rabbitAdmin;
}
@Bean
public SimpleRabbitListenerContainerFactory remoteContainerFactory(ConnectionFactory remoteConnectionFactory,
MessageConverter jackson2JsonMessageConverter) {
SimpleRabbitListenerContainerFactory factory = new SimpleRabbitListenerContainerFactory();
factory.setConnectionFactory(remoteConnectionFactory);
factory.setConcurrentConsumers(1);
factory.setMessageConverter(jackson2JsonMessageConverter);
factory.setMaxConcurrentConsumers(5);
factory.setDefaultRequeueRejected(false); // on error, don't put back in the queue
return factory;
}
现在是好的部分。我有另一个RabbitTemplate我正在调用convertSendAndReceive(),在其上配置了remoteConnectionFactory。
@Bean
public RabbitTemplate payTemplate(ConnectionFactory remoteConnectionFactory,
TopicExchange fromExchange, MessageConverter jackson2JsonMessageConverter) {
RabbitTemplate rabbitTemplate = new RabbitTemplate(remoteConnectionFactory);
rabbitTemplate.setReplyAddress(fromExchange.getName() + "/" + buildMyBindingKey());
rabbitTemplate.setReplyTimeout(30000L);
rabbitTemplate.setMessageConverter(jackson2JsonMessageConverter);
return rabbitTemplate;
}
@Bean
public SimpleMessageListenerContainer payReplyContainer(ConnectionFactory remoteConnectionFactory,
RabbitTemplate payTemplate, Queue fromQueue) {
SimpleMessageListenerContainer container = new SimpleMessageListenerContainer();
container.setConnectionFactory(remoteConnectionFactory);
container.setQueues(fromQueue);
container.setMessageListener(payTemplate);
return container;
}
@Bean
public TopicExchange fromExchange(RabbitAdmin remoteAdmin) {
TopicExchange exchange = new TopicExchange("some.from.exchange", true, false);
exchange.setAdminsThatShouldDeclare(remoteAdmin);
return exchange;
}
@Bean
public Queue fromQueue(RabbitAdmin remoteAdmin) {
Queue queue = new Queue("myReplyQueue");
queue.setAdminsThatShouldDeclare(corporateAdmin);
return queue;
}
private String buildMyBindingKey() {
return "someBindingKeyHere";
}
当我在payTemplate上调用convertSendAndReceive()时,会出现问题。回复收到很好,但几乎似乎收到了两次。当我连接到一个RabbitMQ服务器时,这很有用,但在配置到两个服务器的连接之后,我得到了这个:
2018-06-11 18:29:57,156|WARN||payReplyContainer-1|org.springframework.amqp.rabbit.core.RabbitTemplate|||||Reply received after timeout for 1
2018-06-11 18:29:57,165|WARN||payReplyContainer-1|org.springframework.amqp.rabbit.listener.ConditionalRejectingErrorHandler|||||Execution of Rabbit message listener failed.
org.springframework.amqp.rabbit.listener.exception.ListenerExecutionFailedException: Listener threw exception
at org.springframework.amqp.rabbit.listener.AbstractMessageListenerContainer.wrapToListenerExecutionFailedExceptionIfNeeded(AbstractMessageListenerContainer.java:949)
at org.springframework.amqp.rabbit.listener.AbstractMessageListenerContainer.doInvokeListener(AbstractMessageListenerContainer.java:902)
at org.springframework.amqp.rabbit.listener.AbstractMessageListenerContainer.invokeListener(AbstractMessageListenerContainer.java:790)
at org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer.access$001(SimpleMessageListenerContainer.java:105)
at org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer$1.invokeListener(SimpleMessageListenerContainer.java:208)
at org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer.invokeListener(SimpleMessageListenerContainer.java:1349)
at org.springframework.amqp.rabbit.listener.AbstractMessageListenerContainer.executeListener(AbstractMessageListenerContainer.java:760)
at org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer.doReceiveAndExecute(SimpleMessageListenerContainer.java:1292)
at org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer.receiveAndExecute(SimpleMessageListenerContainer.java:1262)
at org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer.access$1800(SimpleMessageListenerContainer.java:105)
at org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer$AsyncMessageProcessingConsumer.run(SimpleMessageListenerContainer.java:1518)
at java.lang.Thread.run(Thread.java:748)
Caused by: org.springframework.amqp.AmqpRejectAndDontRequeueException: Reply received after timeout
at org.springframework.amqp.rabbit.core.RabbitTemplate.onMessage(RabbitTemplate.java:1759)
at org.springframework.amqp.rabbit.listener.AbstractMessageListenerContainer.doInvokeListener(AbstractMessageListenerContainer.java:899)
... 10 common frames omitted
同样,payTemplate确实得到了它正在等待的回复/响应,但它像容器一样收到了另一条没有人在等待的消息。我很难过。任何帮助表示赞赏。
答案 0 :(得分:0)
实际上,这是一种交换(一种不应该存在的额外约束),它负责复制响应。非常感谢Gary检查我的代码,并且可能没有看错,并提出了一些建议。