当前位置: 首页 > news >正文

Listener method could not be invoked with the incoming message

问题描述

  生产者方代码:

    private void rollbackOrder(long orderId, CorrelationData correlationData) {rabbitTemplate.convertAndSend("order-rollback-exchange","rollback.order",new QuotaRollbackTO(orderId,null,null),correlationData);}

  消费者方代码:

    @RabbitListener(queues = "rollback.order.queue")public void handleRollback(QuotaRollbackTO quotaRollbackTO, Message message, Channel channel) throws Exception {try {//回滚订单的逻辑orderMainMapper.deleteById(quotaRollbackTO.getOrderId());orderProductMapper.deleteById(quotaRollbackTO.getOrderId());// 手动ACKchannel.basicAck(message.getMessageProperties().getDeliveryTag(), false);} catch (Exception e) {System.err.println("消息处理失败:" + e.getMessage());// 拒绝消息并转入死信队列channel.basicReject(message.getMessageProperties().getDeliveryTag(), false);}}

  Rabbit MQ发送消息报错:

org.springframework.amqp.rabbit.listener.exception.ListenerExecutionFailedException: Listener method could not be invoked with the incoming message
Endpoint handler details:
Method [public void org.ragdollcat.order.mqlistener.OrderMQListener.handleRollback(org.ragdollcat.order.to.QuotaRollbackTO,org.springframework.amqp.core.Message,com.rabbitmq.client.Channel) throws java.lang.Exception]


原因分析:

  由于未配置 RabbitMQ 使用 JSON 消息转换器,Spring Boot 默认采用了 SimpleMessageConverter,导致无法将 JSON 数据反序列化为 QuotaRollbackTO 对象,从而造成监听方法调用失败。在错误信息中,可能会发现以下提示:

Caused by: org.springframework.messaging.converter.MessageConversionException: Cannot convert from [[B] to [org.ragdollcat.order.to.QuotaRollbackTO] for GenericMessage [payload=byte[234], headers={amqp_receivedDeliveryMode=PERSISTENT, amqp_receivedRoutingKey=rollback.order, spring_listener_return_correlation=4e708ed8-bfde-4f43-9282-4701c1b5ef19, amqp_receivedExchange=order-rollback-exchange, spring_returned_message_correlation=4591a034-2ee5-4d4c-8a3c-4c95a3b43572, amqp_deliveryTag=1, amqp_consumerQueue=rollback.order.queue, amqp_redelivered=false, id=58a03a74-a8d4-329c-7d26-c229977f4c15, amqp_consumerTag=amq.ctag-0deI5Ts_m6_K32RdEYyDZA, contentType=application/x-java-serialized-object, timestamp=1747560067493}]

  证实了发送端把对象以JDK默认方式(ObjectOutputStream)序列化成 byte[],接收端尝试用 JSON 的方式将这个 byte[] 解析成 QuotaRollbackTO,失败。


解决方案:

  在配置类中,显式使用 JSON 消息转换器,为 RabbitTemplate 设置 Jackson2JsonMessageConverter(或放在Spring Boot的引导类中也可以,引导类本身也是作为一个配置类),这样后续注入的就是自定义的RabbitTemplate

@Configuration
public class RabbitTemplateConfig {@Beanpublic MessageConverter messageConverter() {return new Jackson2JsonMessageConverter();}@Beanpublic RabbitTemplate rabbitTemplate(ConnectionFactory connectionFactory,MessageConverter jacksonMessageConverter) {RabbitTemplate rabbitTemplate = new RabbitTemplate(connectionFactory);// 开启强制投递,必须配置这个 ReturnCallback 才会生效!rabbitTemplate.setMandatory(true);// 设置 ConfirmCallbackrabbitTemplate.setConfirmCallback((correlationData, ack, cause) -> {if (ack) {System.out.println(" 交换机已收到消息:" + correlationData);} else {System.err.println(" 交换机未收到消息:" + cause + ",相关数据:" + correlationData);}});// 设置 ReturnCallbackrabbitTemplate.setReturnCallback((message, replyCode, replyText, exchange, routingKey) -> {System.err.println(" 消息未成功路由到队列:");System.err.println("  原始消息:" + new String(message.getBody()));System.err.println("  应答码:" + replyCode);System.err.println("  原因:" + replyText);System.err.println("  交换机:" + exchange);System.err.println("  路由键:" + routingKey);});//为 RabbitTemplate 设置 `Jackson2JsonMessageConverter`rabbitTemplate.setMessageConverter(jacksonMessageConverter);return rabbitTemplate;}@Beanpublic SimpleRabbitListenerContainerFactory rabbitListenerContainerFactory(ConnectionFactory connectionFactory,MessageConverter jacksonMessageConverter) {SimpleRabbitListenerContainerFactory factory = new SimpleRabbitListenerContainerFactory();factory.setConnectionFactory(connectionFactory);factory.setMessageConverter(jacksonMessageConverter);return factory;}}

  同样地在发送消息时,不应采用对象转换为JSON字符串的写法:

rabbitTemplate.convertAndSend("rollback.order", JSON.toJSONString(rollbackTO));

验证方式:

  临时打印发送内容 headers:

rabbitTemplate.setReturnsCallback(returned -> {Message returnedMessage = returned.getMessage();System.out.println("发送内容类型: " + returnedMessage.getMessageProperties().getContentType());
});

  看到的 contentType 应该是:

“application/json”

相关文章:

  • Linux之基础IO
  • 非线性1无修
  • python + pip 独家秘籍
  • C++ map容器: 插入操作
  • 5.18 day24
  • 新电脑软件配置三 pycharm
  • 【应用开发十】pwm
  • ffmpeg -vf subtitles添加字幕绝对路径问题的解决方法
  • [创业之路-358]:从历史轮回到制度跃迁:中国共产党创业模式的超越性密码
  • 三:操作系统线程管理之用户级线程与内核级线程
  • Milvus(25):搜索迭代器、使用分区密钥
  • 为实时数据构建WebSocket解决方案的挑战
  • Git在与远程仓库建立连接时,不小心输错密码导致连接失败,之后无法弹出用户名密码的输入框解决方案
  • 面试题总结二
  • 记录一次修改nacos安全问题导致服务调用出现404
  • KnowCard:我的知识卡片生成器是怎么炼成的?
  • web中路径问题
  • 能力验证及大练兵活动第一期
  • LeetCode Hot100刷题——除自身以外数组的乘积
  • MyBatis-Plus-Join联表查询
  • 俄乌上周在土耳其直接谈判,外交部回应
  • “80后”北大硕士罗婕履新甘肃宁县县委常委、组织部部长
  • 武康大楼再开发:一栋楼火还不够,要带火街区“朋友圈”
  • 戛纳打破“疑罪从无”惯例,一法国男演员被拒之门外
  • “9+2”复式票,浦东购彩者拿下体彩大乐透1153万头奖
  • 因港而兴,“长江黄金水道”上的宜宾故事