我使用的是spring-boot 1.4.2和rabbitMQ 1.6.5.RELEASE(不使用spring-boot-starter-rabbit)。我的项目中有多个微服务,大多数微服务都包含rabbitMQ消费者。项目中的一个将产生消息。即使消息在队列中可用,也很少有消费者停止从队列中获取消息。如果我重新启动该特定消费者,那么它将开始消费该消息。如果我重新部署任何消费者微服务,那么其他组件上的消费者很少会停止从队列中消费消息,但在队列中我可以看到消息。
查看日志后,我可以找到以下问题
com.sample.global.bookStateUpdate.consumer.BookFailConsumer.execute(com.vodafone.smartlife.provisioning.common.model.Message)
throws com.sample.global.bookStateUpdate.consumer.BookFailConsumer.exception.ConsumerException' threw exception
org.springframework.amqp.rabbit.listener.adapter.MessagingMessageListenerAdapter.invokeHandler(MessagingMessageListenerAdapter.java:138)
org.springframework.amqp.rabbit.listener.adapter.MessagingMessageListenerAdapter.onMessage(MessagingMessageListenerAdapter.java:105)
org.springframework.amqp.rabbit.listener.AbstractMessageListenerContainer.doInvokeListener(AbstractMessageListenerContainer.java:778)
org.springframework.amqp.rabbit.listener.AbstractMessageListenerContainer.invokeListener(AbstractMessageListenerContainer.java:701)
org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer.access$001(SimpleMessageListenerContainer.java:99)
org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer$1.invokeListener(SimpleMessageListenerContainer.java:191)
org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer.invokeListener(SimpleMessageListenerContainer.java:1213)
org.springframework.amqp.rabbit.listener.AbstractMessageListenerContainer.executeListener(AbstractMessageListenerContainer.java:682)
org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer.doReceiveAndExecute(SimpleMessageListenerContainer.java:1191)
org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer.receiveAndExecute(SimpleMessageListenerContainer.java:1175)
org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer.access$1200(SimpleMessageListenerContainer.java:99)
org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer$AsyncMessageProcessingConsumer.run(SimpleMessageListenerContainer.java:1338)\n\tat java.lang.Thread.run(Thread.java:745)\n
Caused by: java.lang.NullPointerException: null
com.sample.global.bookStateUpdate.consumer.BookFailConsumer.execute(BookFailConsumer.java:54)
sun.reflect.GeneratedMethodAccessor149.invoke(Unknown Source)\n\tat sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
java.lang.reflect.Method.invoke(Method.java:498)org.springframework.messaging.handler.invocation.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:197)
org.springframework.messaging.handler.invocation.InvocableHandlerMethod.invoke(InvocableHandlerMethod.java:115)
org.springframework.amqp.rabbit.listener.adapter.HandlerAdapter.invoke(HandlerAdapter.java:49)
org.springframework.amqp.rabbit.listener.adapter.MessagingMessageListenerAdapter.invokeHandler(MessagingMessageListenerAdapter.java:125)... 12 common frames omitted\n
所以杰克逊似乎无法将我的信息转换为json。所以在我的消费者而不是消耗我已经消耗的实际对象 org.springframework.amqp.core.Message 然后我手动将其转换为我的自定义对象。
我可以知道为什么spring-rabbit无法将消息转换为json?
请找到以下配置&消费者文件变更
package com.sample.global.rabbit.configuration;
import org.springframework.amqp.rabbit.annotation.EnableRabbit;
import org.springframework.amqp.rabbit.config.SimpleRabbitListenerContainerFactory;
import org.springframework.amqp.rabbit.connection.CachingConnectionFactory;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.amqp.rabbit.test.RabbitListenerTest;
import org.springframework.amqp.support.converter.Jackson2JsonMessageConverter;
import org.springframework.amqp.support.converter.MessageConverter;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
@Configuration
@EnableRabbit
@RabbitListenerTest(capture = true, spy = true)
public class RabbitMqConfiguration {
@Bean
public SimpleRabbitListenerContainerFactory rabbitListenerContainerFactory() {
SimpleRabbitListenerContainerFactory factory = new SimpleRabbitListenerContainerFactory();
factory.setConnectionFactory(connectionFactory());
factory.setConcurrentConsumers(15);
factory.setMaxConcurrentConsumers(15);
factory.setMessageConverter(jsonMessageConverter());
return factory;
}
@Bean
public CachingConnectionFactory connectionFactory()
{
CachingConnectionFactory connectionFactory = new CachingConnectionFactory("http://localhost:15672");
connectionFactory.setUsername("guest");
connectionFactory.setPassword("guest");
connectionFactory.setRequestedHeartBeat(10);
return connectionFactory;
}
@Bean
public MessageConverter jsonMessageConverter()
{
return new Jackson2JsonMessageConverter();
}
@Bean(name = "MainTemplate")
@Primary
public RabbitTemplate rabbitTemplate()
{
RabbitTemplate template = new RabbitTemplate(connectionFactory());
template.setMessageConverter(jsonMessageConverter());
return template;
}
}
消费
package com.sample.global.rabbit.consumer;
import org.springframework.amqp.core.Message;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.amqp.rabbit.annotation.Exchange;
import org.springframework.amqp.rabbit.annotation.Queue;
import org.springframework.amqp.rabbit.annotation.QueueBinding;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Component;
@Component
public class BookFailConsumer {
private static final Logger logger = LoggerFactory.getLogger(BookFailConsumer.class);
private static final ObjectMapper objectMapper = new ObjectMapper();
@Autowired
@Qualifier(value = "MainTemplate")
private RabbitTemplate rabbitTemplate;
@RabbitListener(
id = "book",
bindings = @QueueBinding(
value = @Queue(value = "sample.queue", durable = "true"),
exchange = @Exchange(value = "sample.exchange", durable = "true", delayed = "true"),
key = "sample.queue"
)
)
public void handle(Message messageObject) {
com.sample.global.rabbit.consumer.model.Message message = null;
try {
message = convertMessageBodyToTransaction(messageObject.getBody());
//After manual JSON conversion it works fine.
} catch (Exception e) {
e.printStackTrace();
}
}
public Message convertMessageBodyToTransaction(byte[] messageBody) throws BadRequestException {
com.sample.global.rabbit.consumer.model.Message message = null;
String body = null;
try {
body = new String(messageBody, "UTF-8");
logger.debug("Message body converted successfully to string: {}", body);
} catch (UnsupportedEncodingException e) {
throw new BadRequestException(e);
}
try {
message = objectMapper.readValue(body, Message.class);
logger.debug("Message body mapped successfully to Message object: {}", message.toString());
} catch (Exception e){
logger.error("Message conversion failed for the following message body: {}", body);
throw new BadRequestException(e);
}
return message;
}
}
有没有办法避免手动转换?任何提示都有助于解决此问题
答案 0 :(得分:0)
日志显示原因是BookFailConsumer.execute中的NullpointerException
所以这个消费者正在接收消息而不是BookConsumer,正如您所期望的那样。 您需要检查,为什么调用了BookFailConsumer并且那里出了什么问题。 (你没有发布BookFailConsumer的代码)