繁体   English   中英

带有 Spring-boot 的 Kafka:消费者通过 ConsumerRecord 消费 java.lang.Object(任何/所有对象)

[英]Kafka with Spring-boot: Consumer to consume java.lang.Object( Any/all object) via ConsumerRecord

所以我正在使用 spring-boot2.1.6 并集成 kafka 消费者来消费在主题上发布的任何类型的消息。 作为参考,我正在关注https://docs.spring.io/spring-boot/docs/2.1.6.RELEASE/reference/htmlsingle/

所以我在我的pom中有依赖:

    <dependency>
        <groupId>org.springframework.kafka</groupId>
        <artifactId>spring-kafka</artifactId>
    </dependency>

我在 application.yml 中配置

spring:
  kafka:
    bootstrap-servers: localhost:9092
    consumer:
      group-id: foo
      auto-offset-reset: earliest
      key-deserializer: org.apache.kafka.common.serialization.StringDeserializer
      value-deserializer: org.springframework.kafka.support.serializer.JsonDeserializer
      properties:
        spring:
          json:
            value:
              default:
                type: java.lang.Object

最后这是我的监听器代码:

 @KafkaListener(topics = "videoEnrichedEvents")
    public void consume(@Payload VideoEnrichedEventsvideoEnrichedEvents){
        LOGGER.debug("Consumed message :"+videoEnrichedEvents);
        System.out.println("Consumed Message :"videoEnrichedEvents);
    }

由于我有不同的主题和不同的消费者,我希望消费者配置足够通用,以便我可以读取任何 object,然后将其委托给处理处理程序。 在错误日志中,我可以看到:

Caused by: org.springframework.messaging.converter.MessageConversionException: Cannot handle message; nested exception is org.springframework.messaging.converter.MessageConversionException: Cannot convert from [java.util.LinkedHashMap] to [com.calamp.connect.vs.model.VideoEnrichedEvents] for GenericMessage [payload={anyotherjson={groups=null, id=0, driverName=from Kusum's console, deviceIdType=null, assetId=null, operatorId=null, avlEventTime=null, videoLink=null, tripId=null, avlEventUuid=null, deviceId=null, appMessageUuid=null, parentAccountList=null, appmsgEventTime=null, enrichedMessage=null, accountId=null}}, headers={kafka_offset=9, kafka_consumer=org.apache.kafka.clients.consumer.KafkaConsumer@18213932, kafka_timestampType=CREATE_TIME, kafka_receivedMessageKey=null, kafka_receivedPartitionId=0, kafka_receivedTopic=videoEnrichedEvents, kafka_receivedTimestamp=1590218109430}], failedMessage=GenericMessage [payload={anyotherjson={groups=null, id=0, driverName=from Kusum's console, deviceIdType=null, assetId=null, operatorId=null, avlEventTime=null, videoLink=null, tripId=null, avlEventUuid=null, deviceId=null, appMessageUuid=null, parentAccountList=null, appmsgEventTime=null, enrichedMessage=null, accountId=null}}, headers={kafka_offset=9, kafka_consumer=org.apache.kafka.clients.consumer.KafkaConsumer@18213932, kafka_timestampType=CREATE_TIME, kafka_receivedMessageKey=null, kafka_receivedPartitionId=0, kafka_receivedTopic=videoEnrichedEvents, kafka_receivedTimestamp=1590218109430}]

经过一番谷歌搜索后,我发现到处都使用了 ConsumerRecord 而不是 LinkedHashMap。
我的新代码如下所示:

 @KafkaListener(topics = "videoEnrichedEvents")
    public void consume(@Payload ConsumerRecord consumerRecord){
        LOGGER.debug("Consumed message!!!Full :"+consumerRecord);
        System.out.println("Consumed Message!!! Actual object :"+((LinkedHashMap)consumerRecord.value()));
    }

它在技术上处理发送给我的任何 object。 所以它解决了我的目的。 但我的问题是为什么 ConsumerRecord 而不是 LinkedHashMap? 有什么具体原因吗?

处理这个问题的最简单方法是将ByteArrayDeserializerByteArrayJsonMessageConverter bean 一起使用(只需将其添加到应用程序上下文中,Boot 就会将其连接进去)。

这样,从 JSON 的转换被推迟到我们调用该方法之前,所以我们知道目标类型是什么。

请参阅https://docs.spring.io/spring-kafka/docs/2.5.0.RELEASE/reference/html/#messaging-message-conversion

注意:此方法不能与类级别的侦听器和@KafkaHandler方法一起使用,因为在这种情况下,我们使用 select 的类型来调用哪个方法。

方法签名很灵活,可以采用 ConsumerRecord 或记录中包含的反序列化 object。 后者依赖于将传入消息转换为方法签名中的类型的反序列化。 If Jackson cannot determine what type the incoming JSON message is then it will deserialize to a HashMap, as JSON is effectively just a map and so it is providing exactly what you asked for - an Object (where a LinkedHashMap is the only Object it is able使用可用信息进行创建)。

因此,您看到的行为是因为反序列化程序无法将消息反序列化为特定的 class,因此方法签名可以接受 Map 或 ConsumerRecord - 其中 ConsumerRecord 是任何消息的有效参数,无论反序列化如何。

如果您想以这种方式处理不同的类型,最好使用自定义反序列化器,它可以查看消息的某些方面并创建正确的 class 的实例,指定反序列化器而不是您在 yaml 中拥有的 JsonDeserializer。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM