SpringbootKaka批量消费报Listener method could not be invoked with the incoming message

本文详细记录了一起Spring Kafka消费者在批量监听时遇到的类型转换异常问题,通过分析错误日志,发现是由于消息转换错误导致。在尝试多种解决方案后,最终通过设置`spring.kafka.listener.type=batch`修复了问题。此外,还分享了生产者代码、完整的配置信息以及问题出现的背景,为读者提供了解决类似问题的参考。

结论:在配置文件中加上spring.kafka.listener.type=batch 。

完整报错信息如下:

org.springframework.kafka.listener.ListenerExecutionFailedException: Listener method could not be invoked with the incoming message
Endpoint handler details:
Method [public void com.kafka.gateway.consumer.heartBeatConsumer.listensGroupPro(org.apache.kafka.clients.consumer.ConsumerRecords<java.lang.String, java.lang.String>,org.springframework.kafka.support.Acknowledgment)]
Bean [com.kafka.gateway.consumer.heartBeatConsumer@3cceaa40]; nested exception is org.springframework.messaging.converter.MessageConversionException: Cannot handle message; nested exception is org.springframework.messaging.converter.MessageConversionException: Cannot convert from [java.lang.String] to [org.apache.kafka.clients.consumer.ConsumerRecords] for GenericMessage [payload={"index":"1000","ip":"A6-B1-C1-D6-FE-34","timestamp":1638263084,"type":"6","value":[]}, headers={kafka_offset=71, kafka_consumer=org.apache.kafka.clients.consumer.KafkaConsumer@585c68b4, kafka_timestampType=CREATE_TIME, kafka_receivedPartitionId=0, kafka_receivedMessageKey=key, kafka_receivedTopic=heartbeat4, kafka_receivedTimestamp=1638495075056, kafka_acknowledgment=Acknowledgment for heartbeat4-0@71, kafka_groupId=gateway2}], failedMessage=GenericMessage [payload={"index":"1000","ip":"A6-B1-C1-D6-FE-34","timestamp":1638263084,"type":"6","value":[]}, headers={kafka_offset=71, kafka_consumer=org.apache.kafka.clients.consumer.KafkaConsumer@585c68b4, kafka_timestampType=CREATE_TIME, kafka_receivedPartitionId=0, kafka_receivedMessageKey=key, kafka_receivedTopic=heartbeat4, kafka_receivedTimestamp=1638495075056, kafka_acknowledgment=Acknowledgment for heartbeat4-0@71, kafka_groupId=gateway2}]; nested exception is org.springframework.messaging.converter.MessageConversionException: Cannot handle message; nested exception is org.springframework.messaging.converter.MessageConversionException: Cannot convert from [java.lang.String] to [org.apache.kafka.clients.consumer.ConsumerRecords] for GenericMessage [payload={"index":"1000","ip":"A6-B1-C1-D6-FE-34","timestamp":1638263084,"type":"6","value":[]}, headers={kafka_offset=71, kafka_consumer=org.apache.kafka.clients.consumer.KafkaConsumer@585c68b4, kafka_timestampType=CREATE_TIME, kafka_receivedPartitionId=0, kafka_receivedMessageKey=key, kafka_receivedTopic=heartbeat4, kafka_receivedTimestamp=1638495075056, kafka_acknowledgment=Acknowledgment for heartbeat4-0@71, kafka_groupId=gateway2}], failedMessage=GenericMessage [payload={"index":"1000","ip":"A6-B1-C1-D6-FE-34","ti
这个问题: ``` Listener method could not be invoked with the incoming message ``` 说明 **Spring 无法正确地将 RabbitMQ 消息转换为方法参数**,也就是 Spring 无法调用你的监听方法。 --- ## 🧠 问题分析 你修改后的代码逻辑是正确的: ```java public void queueA(List<Order> orders, Channel channel, @Header(AmqpHeaders.DELIVERY_TAG) long[] deliveryTags) ``` 但 Spring AMQP **默认的消息转换器(MessageConverter)** 可能无法正确地将 RabbitMQ 的消息反序列化为 `List<Order>` 类型。 ### 🔍 常见原因如下: 1. **消息体是 JSON 字符串**,但 Spring 没有配置合适的 `MessageConverter` 来将其转换为 `List<Order>`。 2. **Spring 不支持直接将 JSON 转换为泛型集合(如 List<T>)**,除非你明确告诉它目标类型。 3. **使用了默认的 `SimpleMessageConverter`**,它只能处理 `String`, `Byte[]`, 和 `Serializable` 类型。 --- ## ✅ 解决方案 你需要配置一个支持泛型的 `MessageConverter`,推荐使用 `Jackson2JsonMessageConverter`,并配合 `GenericTypeResolver` 来处理 `List<Order>`。 ### ✅ 步骤一:配置 `Jackson2JsonMessageConverter` ```java @Configuration public class RabbitConfig { @Bean public MessageConverter jackson2JsonMessageConverter(ObjectMapper objectMapper) { return new Jackson2JsonMessageConverter(objectMapper, "UTF-8"); } @Bean public RabbitListenerContainerFactory<?> batchContainerFactory(ConnectionFactory connectionFactory, MessageConverter jackson2JsonMessageConverter) { SimpleRabbitListenerContainerFactory factory = new SimpleRabbitListenerContainerFactory(); factory.setConnectionFactory(connectionFactory); factory.setMessageConverter(jackson2JsonMessageConverter); factory.setBatchListener(true); // 开启批量监听 factory.setPrefetchCount(10); // 批量大小 return factory; } } ``` ### ✅ 步骤二:确保 `Order` 是可序列化的,并有无参构造函数 ```java public class Order implements Serializable { private String orderId; private BigDecimal amount; // getters/setters } ``` ### ✅ 步骤三:修改监听方法签名,使用 `@Payload` 明确指定反序列化目标 ```java @RabbitListener(queues = "queueA", containerFactory = "batchContainerFactory") public void queueA(@Payload List<Order> orders, Channel channel, @Header(AmqpHeaders.DELIVERY_TAG) long[] deliveryTags) throws IOException { try { for (Order order : orders) { System.out.println(order.toString()); } // 确认整个批次的消息 channel.basicAck(deliveryTags[deliveryTags.length - 1], true); } catch (Exception e) { // 拒绝整个批次的消息,并重新入队 channel.basicNack(deliveryTags[deliveryTags.length - 1], true, true); } } ``` ### ✅ 说明: - `@Payload` 告诉 Spring 使用 `MessageConverter` 反序列化消息体。 - `Jackson2JsonMessageConverter` 支持将 JSON 转换为 `List<Order>`。 - 如果你使用的是 Spring Boot,它已经默认配置了 `ObjectMapper`,可以直接注入使用。 --- ## ✅ 验证方法 你可以手动发送一条 JSON 格式的消息到 `queueA` 测试: ```json [ { "orderId": "1001", "amount": 100.00 }, { "orderId": "1002", "amount": 200.00 } ] ``` --- ##
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值