不使用POJO的Kafka Avro解串器

时间:2019-05-16 03:54:12

标签: apache-kafka avro

我已经使用带有生成的Java源代码的Avro模式文件编写了Kafka Avro Deserializer。要求是不要使用POJO。如何使以下代码不使用POJO和通用模式转换。

    import java.util.Arrays;
    import java.util.Map;
    import org.apache.avro.generic.GenericDatumReader;
    import org.apache.avro.generic.GenericRecord;
    import org.apache.avro.io.DatumReader;
    import org.apache.avro.io.Decoder;
    import org.apache.avro.io.DecoderFactory;
    import org.apache.kafka.common.errors.SerializationException;
    import org.apache.kafka.common.serialization.Deserializer;
    import com.example.org.model.Person;

    public class AvroDeserializer implements Deserializer<GenericRecord> {

     @Override
     public void close() {

     }

     @Override
     public void configure(Map<String, ?> configs, boolean isKey) {

    }

    @Override
    public GenericRecord deserialize(String topic, byte[] data) {
    try {
      GenericRecord result = null;

      if (data != null) {
        DatumReader<Person> reader = new SpecificDatumReader<> 
     (Person.getSchema());

        Decoder decoder = DecoderFactory.get().binaryDecoder(data, null);
        result = (GenericRecord) reader.read(null, decoder);
      }
      return result;
     } catch (Exception ex) {
      throw new SerializationException(
      "Can't deserialize data '" + Arrays.toString(data) + "' from topic '" + topic + "'", ex);
    }
  }
    }

如何使此代码不使用POJO。

2 个答案:

答案 0 :(得分:0)

如果您在Serilizer中使用POJO类,那么您将存储模式以及数据,这些数据将在解析消息时变慢,并且还会在存储级别占用额外的空间。 您必须在SerilizerDeSerilizer中进行更改。

要解决此问题,请使用Schema RegistrySchema Registry

架构注册表的基本思想是,在将数据读写到主题时,生产者/消费者将引用avro架构。

我们不想像您暗示的那样为每个数据编写模式-通常,模式大于您的数据!那样会浪费时间在每次读取时进行解析,也浪费了资源(网络,磁盘,CPU)

我建议您通过以下链接获取代码以及对该主题的详细描述。

https://blog.cloudera.com/blog/2018/07/robust-message-serialization-in-apache-kafka-using-apache-avro-part-1/

答案 1 :(得分:0)

有几种方法可以做到这一点。您可以将其添加到构造函数中:

protected final Class<T> targetType;

public AvroDeserializer(Class<T> targetType) {
    this.targetType = targetType;
}

并使用targetType反序列化:

        SpecificDatumReader<GenericRecord> datumReader =
            new SpecificDatumReader<>(targetType.newInstance().getSchema());

然后,从客户端使用反序列化器:

AvroEmbeddedDeserializer<Test> avroEmbeddedDeserializer = new AvroEmbeddedDeserializer<>(Test.class);

final KafkaConsumer<String, Test> consumer = new KafkaConsumer<>(props, stringDeserializer, avroEmbeddedDeserializer);

请注意,使用这种方法时,您不能使用反序列化属性来配置您的使用者,因为它使用了空的构造函数。