繁体   English   中英

Kafka Avro 使用模式注册表将序列化/反序列化为具体类型失败

[英]Kafka Avro serialize/deserialize into concrete type using schema registry failing

我似乎无法在他们的具体 avro 实现中使用消息,我得到以下异常:

class org.apache.avro.generic.GenericData$Record cannot be cast to class my.package.MyConcreteClass

这是代码(我使用Spring Boot

MyProducer.java

private final KafkaTemplate<String, MyConcreteClass> kafkaTemplate;

public PositionProducer(KafkaTemplate<String, MyConcreteClass> kafkaTemplate) {
    this.kafkaTemplate = kafkaTemplate;
}

public void sendMessage(MyConcreteClass myConcreteClass) {
    this.kafkaTemplate.send(topic, myConcreteClass);
}

MyConsumer.java

@KafkaListener(topics = "#{'${consumer.topic.name}'}", groupId = "#{'${spring.kafka.consumer.group-id}'}")
public void listen(MyConcreteClass incomingMsg) {
    //handle
}

请注意,如果我将所有内容更改为GenericRecord ,则反序列化工作正常,因此我知道所有配置(未粘贴)均已正确配置。

同样重要的是要注意我自己没有注册模式,而是让我的客户端代码为我做。

有任何想法吗?

编辑:

配置:

@Bean
public ConsumerFactory<String, MyConcreteClass> consumerFactory() {
    Map<String, Object> props = new HashMap<>();
    props.put(ConsumerConfig.BOOTSTRAP_SERVERS_CONFIG, bootstrapServers);
    props.put(ConsumerConfig.GROUP_ID_CONFIG, groupId);
    props.put(ConsumerConfig.KEY_DESERIALIZER_CLASS_CONFIG, "org.apache.kafka.common.serialization.StringDeserializer");
    props.put(ConsumerConfig.VALUE_DESERIALIZER_CLASS_CONFIG, "io.confluent.kafka.serializers.KafkaAvroDeserializer");
    props.put(KafkaAvroDeserializerConfig.SCHEMA_REGISTRY_URL_CONFIG, schemaRegistryUrl);
    return new DefaultKafkaConsumerFactory<>(props);
}

MyConcreteClass 需要扩展SpecificRecord

您可以使用 Avro maven 插件从架构中生成它

然后您必须配置序列化程序以知道您要使用特定记录

props.put(KafkaAvroDeserializerConfig.SPECIFIC_AVRO_READER_CONFIG, "true") ;

除了 OneCricketeer 的回答,我在设置了特定的 avro reader 配置后遇到了另一个 java.lang.ClassCastException。 nested exception is java.lang.ClassCastException: class my.package.Envelope cannot be cast to class my.package.Envelope (my.package.Envelope is in unnamed module of loader 'app'; my.package.Envelope is in unnamed module of loader org.springframework.boot.devtools.restart.classloader.RestartClassLoader @3be312bd); 似乎 spring boot devtools 将类包装在它的重新加载器模块中,导致 jvm 认为这是一个不同的类。

我删除了 pom 中的 spring boot devtools,现在它终于按预期工作了。

<!-- Remove this from pom.xml -->
<dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-devtools</artifactId>
        <scope>runtime</scope>
        <optional>true</optional>
</dependency>

我被和你一样的问题阻止了。 问题是KafkaAvroDeserializer将消息反序列化为GenericData$Record ,因此 spring kafka 正在搜索用 @KafkaListener 注释的@KafkaListener以具有带有此类参数的@KafkaHandler方法。

您需要将此属性添加到您的 spring kafka 配置中,以便反序列化器可以直接返回您之前需要使用 avro 插件生成的SpecificRecord类:

spring:
  kafka:
    properties:
      specific.avro.reader: true

那么你的消费者可能是这样的

@KafkaListener(...)
public void consumeCreation(MyAvroGeneratedClass specificRecord) {
    log.info("Consuming record: {}", specificRecord);
}

您需要自定义您的消费者配置。 ContentDeserializer 需要是一个 KafkaAvroDeserializer,并引用您的架构注册表。

暂无
暂无

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

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