我正在尝试使用Kafka-Spring(spring-boot)实现Kafka使用者。我使用生产者发送消息,但Spring引发异常,并且由于该异常而未调用我的侦听器方法。
这是我的侦听器方法:
@Service
public class KafkaExchangeApi {
@KafkaListener(topics = ORDER_TOPIC, groupId = "group_id")
public void handleOrderResponse(@Payload GatewayOrder response) {
System.println("order caught");
}
}
@AllArgsConstructor
@NoArgsConstructor(force = true)
@Builder
@Getter
@ToString
public class GatewayOrder {
private final long uid;
private final long orderId;
private final int userCookie;
private final long size;
private final OrderAction action;
private final OrderType orderType;
private final String symbol;
// mutable fields
private List<GatewayDeal> deals = new ArrayList<>();
@Setter
private BigDecimal price;
@Setter
private long filled;
@Setter
private GatewayOrderState state;
}
这是我的配置:
server:
port: 9000
spring:
kafka:
consumer:
bootstrap-servers: 192.168.1.3:9092
group-id: group-id
auto-offset-reset: earliest
key-deserializer: org.apache.kafka.common.serialization.StringDeserializer
value-deserializer: org.apache.kafka.common.serialization.StringDeserializer
producer:
bootstrap-servers: 192.168.1.3:9092
key-deserializer: org.apache.kafka.common.serialization.StringDeserializer
value-deserializer: org.apache.kafka.common.serialization.StringDeserializer
我认为生产者发送的JSON消息格式错误,我测试了是否可以使用JSON解析器对其进行解析,并确认可以对其进行解析...
那么,为什么我会收到此异常?
020-09-10 17:04:41.878 INFO 5946 --- [ntainer#1-0-C-1] o.a.k.c.c.internals.SubscriptionState : [Consumer clientId=consumer-group_id-2, groupId=group_id] Resetting offset for partition order-0 to offset 0.
2020-09-10 17:04:41.879 INFO 5946 --- [ntainer#1-0-C-1] o.s.k.l.KafkaMessageListenerContainer : group_id: partitions assigned: [order-0]
2020-09-10 17:04:55.250 ERROR 5946 --- [ntainer#1-0-C-1] o.s.k.l.SeekToCurrentErrorHandler : Backoff none exhausted for ConsumerRecord(topic = order, partition = 0, leaderEpoch = 0, offset = 0, CreateTime = 1599746694173, serialized key size = -1, serialized value size = 160, headers = RecordHeaders(headers = [], isReadOnly = false), key = null, value = {"uid":1, "orderId":1, "userCookie": 0, "size": 1, "action": "ASK", "orderType": "IOC", "symbol": "ABC", "deals":null, "price":1, "filled": 0, "state":"ACTIVE"})
org.springframework.kafka.listener.ListenerExecutionFailedException: Listener method could not be invoked with the incoming message
Endpoint handler details:
Method [public void tradeapi.service.KafkaExchangeApi.handleOrderResponse( tradeapi.model.internal.GatewayOrder)]
Bean [ tradeapi.service.KafkaExchangeApi@2143ea5e]; 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 [ tradeapi.model.internal.GatewayOrder] for GenericMessage [payload={"uid":1, "orderId":1, "userCookie": 0, "size": 1, "action": "ASK", "orderType": "IOC", "symbol": "ABC", "deals":null, "price":1, "filled": 0, "state":"ACTIVE"}, headers={kafka_offset=0, kafka_consumer=org.apache.kafka.clients.consumer.KafkaConsumer@fb7548f, kafka_timestampType=CREATE_TIME, kafka_receivedPartitionId=0, kafka_receivedTopic=order, kafka_receivedTimestamp=1599746694173, kafka_groupId=group_id}], failedMessage=GenericMessage [payload={"uid":1, "orderId":1, "userCookie": 0, "size": 1, "action": "ASK", "orderType": "IOC", "symbol": "ABC", "deals":null, "price":1, "filled": 0, "state":"ACTIVE"}, headers={kafka_offset=0, kafka_consumer=org.apache.kafka.clients.consumer.KafkaConsumer@fb7548f, kafka_timestampType=CREATE_TIME, kafka_receivedPartitionId=0, kafka_receivedTopic=order, kafka_receivedTimestamp=1599746694173, kafka_groupId=group_id}]; 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 [ tradeapi.model.internal.GatewayOrder] for GenericMessage [payload={"uid":1, "orderId":1, "userCookie": 0, "size": 1, "action": "ASK", "orderType": "IOC", "symbol": "ABC", "deals":null, "price":1, "filled": 0, "state":"ACTIVE"}, headers={kafka_offset=0, kafka_consumer=org.apache.kafka.clients.consumer.KafkaConsumer@fb7548f, kafka_timestampType=CREATE_TIME, kafka_receivedPartitionId=0, kafka_receivedTopic=order, kafka_receivedTimestamp=1599746694173, kafka_groupId=group_id}], failedMessage=GenericMessage [payload={"uid":1, "orderId":1, "userCookie": 0, "size": 1, "action": "ASK", "orderType": "IOC", "symbol": "ABC", "deals":null, "price":1, "filled": 0, "state":"ACTIVE"}, headers={kafka_offset=0, kafka_consumer=org.apache.kafka.clients.consumer.KafkaConsumer@fb7548f, kafka_timestampType=CREATE_TIME, kafka_receivedPartitionId=0, kafka_receivedTopic=order, kafka_receivedTimestamp=1599746694173, kafka_groupId=group_id}]
at org.springframework.kafka.listener.KafkaMessageListenerContainer$ListenerConsumer.decorateException(KafkaMessageListenerContainer.java:1925) ~[spring-kafka-2.5.5.RELEASE.jar:2.5.5.RELEASE]
at org.springframework.kafka.listener.KafkaMessageListenerContainer$ListenerConsumer.invokeErrorHandler(KafkaMessageListenerContainer.java:1913) ~[spring-kafka-2.5.5.RELEASE.jar:2.5.5.RELEASE]
at org.springframework.kafka.listener.KafkaMessageListenerContainer$ListenerConsumer.doInvokeRecordListener(KafkaMessageListenerContainer.java:1812) ~[spring-kafka-2.5.5.RELEASE.jar:2.5.5.RELEASE]
at org.springframework.kafka.listener.KafkaMessageListenerContainer$ListenerConsumer.doInvokeWithRecords(KafkaMessageListenerContainer.java:1739) ~[spring-kafka-2.5.5.RELEASE.jar:2.5.5.RELEASE]
at org.springframework.kafka.listener.KafkaMessageListenerContainer$ListenerConsumer.invokeRecordListener(KafkaMessageListenerContainer.java:1636) ~[spring-kafka-2.5.5.RELEASE.jar:2.5.5.RELEASE]
at org.springframework.kafka.listener.KafkaMessageListenerContainer$ListenerConsumer.invokeListener(KafkaMessageListenerContainer.java:1366) ~[spring-kafka-2.5.5.RELEASE.jar:2.5.5.RELEASE]
at org.springframework.kafka.listener.KafkaMessageListenerContainer$ListenerConsumer.pollAndInvoke(KafkaMessageListenerContainer.java:1082) ~[spring-kafka-2.5.5.RELEASE.jar:2.5.5.RELEASE]
at org.springframework.kafka.listener.KafkaMessageListenerContainer$ListenerConsumer.run(KafkaMessageListenerContainer.java:990) ~[spring-kafka-2.5.5.RELEASE.jar:2.5.5.RELEASE]
at java.base/java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:515) ~[na:na]
at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:264) ~[na:na]
at java.base/java.lang.Thread.run(Thread.java:834) ~[na:na]
Caused by: org.springframework.messaging.converter.MessageConversionException: Cannot handle message; nested exception is org.springframework.messaging.converter.MessageConversionException: Cannot convert from [java.lang.String] to [ tradeapi.model.internal.GatewayOrder] for GenericMessage [payload={"uid":1, "orderId":1, "userCookie": 0, "size": 1, "action": "ASK", "orderType": "IOC", "symbol": "ABC", "deals":null, "price":1, "filled": 0, "state":"ACTIVE"}, headers={kafka_offset=0, kafka_consumer=org.apache.kafka.clients.consumer.KafkaConsumer@fb7548f, kafka_timestampType=CREATE_TIME, kafka_receivedPartitionId=0, kafka_receivedTopic=order, kafka_receivedTimestamp=1599746694173, kafka_groupId=group_id}], failedMessage=GenericMessage [payload={"uid":1, "orderId":1, "userCookie": 0, "size": 1, "action": "ASK", "orderType": "IOC", "symbol": "ABC", "deals":null, "price":1, "filled": 0, "state":"ACTIVE"}, headers={kafka_offset=0, kafka_consumer=org.apache.kafka.clients.consumer.KafkaConsumer@fb7548f, kafka_timestampType=CREATE_TIME, kafka_receivedPartitionId=0, kafka_receivedTopic=order, kafka_receivedTimestamp=1599746694173, kafka_groupId=group_id}]
at org.springframework.kafka.listener.adapter.MessagingMessageListenerAdapter.invokeHandler(MessagingMessageListenerAdapter.java:340) ~[spring-kafka-2.5.5.RELEASE.jar:2.5.5.RELEASE]
at org.springframework.kafka.listener.adapter.RecordMessagingMessageListenerAdapter.onMessage(RecordMessagingMessageListenerAdapter.java:86) ~[spring-kafka-2.5.5.RELEASE.jar:2.5.5.RELEASE]
at org.springframework.kafka.listener.adapter.RecordMessagingMessageListenerAdapter.onMessage(RecordMessagingMessageListenerAdapter.java:51) ~[spring-kafka-2.5.5.RELEASE.jar:2.5.5.RELEASE]
at org.springframework.kafka.listener.KafkaMessageListenerContainer$ListenerConsumer.doInvokeOnMessage(KafkaMessageListenerContainer.java:1880) ~[spring-kafka-2.5.5.RELEASE.jar:2.5.5.RELEASE]
at org.springframework.kafka.listener.KafkaMessageListenerContainer$ListenerConsumer.invokeOnMessage(KafkaMessageListenerContainer.java:1862) ~[spring-kafka-2.5.5.RELEASE.jar:2.5.5.RELEASE]
at org.springframework.kafka.listener.KafkaMessageListenerContainer$ListenerConsumer.doInvokeRecordListener(KafkaMessageListenerContainer.java:1799) ~[spring-kafka-2.5.5.RELEASE.jar:2.5.5.RELEASE]
... 8 common frames omitted
Caused by: org.springframework.messaging.converter.MessageConversionException: Cannot convert from [java.lang.String] to [ tradeapi.model.internal.GatewayOrder] for GenericMessage [payload={"uid":1, "orderId":1, "userCookie": 0, "size": 1, "action": "ASK", "orderType": "IOC", "symbol": "ABC", "deals":null, "price":1, "filled": 0, "state":"ACTIVE"}, headers={kafka_offset=0, kafka_consumer=org.apache.kafka.clients.consumer.KafkaConsumer@fb7548f, kafka_timestampType=CREATE_TIME, kafka_receivedPartitionId=0, kafka_receivedTopic=order, kafka_receivedTimestamp=1599746694173, kafka_groupId=group_id}]
at org.springframework.messaging.handler.annotation.support.PayloadMethodArgumentResolver.resolveArgument(PayloadMethodArgumentResolver.java:145) ~[spring-messaging-5.2.8.RELEASE.jar:5.2.8.RELEASE]
at org.springframework.kafka.annotation.KafkaListenerAnnotationBeanPostProcessor$KafkaNullAwarePayloadArgumentResolver.resolveArgument(KafkaListenerAnnotationBeanPostProcessor.java:901) ~[spring-kafka-2.5.5.RELEASE.jar:2.5.5.RELEASE]
at org.springframework.messaging.handler.invocation.HandlerMethodArgumentResolverComposite.resolveArgument(HandlerMethodArgumentResolverComposite.java:117) ~[spring-messaging-5.2.8.RELEASE.jar:5.2.8.RELEASE]
at org.springframework.messaging.handler.invocation.InvocableHandlerMethod.getMethodArgumentValues(InvocableHandlerMethod.java:148) ~[spring-messaging-5.2.8.RELEASE.jar:5.2.8.RELEASE]
at org.springframework.messaging.handler.invocation.InvocableHandlerMethod.invoke(InvocableHandlerMethod.java:116) ~[spring-messaging-5.2.8.RELEASE.jar:5.2.8.RELEASE]
at org.springframework.kafka.listener.adapter.HandlerAdapter.invoke(HandlerAdapter.java:48) ~[spring-kafka-2.5.5.RELEASE.jar:2.5.5.RELEASE]
at org.springframework.kafka.listener.adapter.MessagingMessageListenerAdapter.invokeHandler(MessagingMessageListenerAdapter.java:329) ~[spring-kafka-2.5.5.RELEASE.jar:2.5.5.RELEASE]
... 13 common frames omitted
答案 0 :(得分:0)
使用StringDeserializer
,您需要向应用程序中添加JsonMessageConverter
@Bean
。请参见https://docs.spring.io/spring-kafka/docs/2.6.0/reference/html/#messaging-message-conversion-引导程序会将其自动配置到侦听器容器工厂中。
使用ByteArrayDeserializer
避免不必要的从byte[]
到String
的转换,效率更高。
或者您可以对kafka使用者配置使用经过适当配置的JsonDeserializer
。
无论哪种方式,您都需要将Jackson添加到类路径中。