J'essaie de construire un POC avec Kafka 0.8.1. J'utilise ma propre classe Java comme une Kafka message qui a un tas de types de données String. Je ne peux pas utiliser la classe de sérialiseur par défaut ou la classe de sérialiseur String fournie avec la bibliothèque Kafka. Je suppose que je dois écrire mon propre sérialiseur et le nourrir dans les propriétés du producteur. Si vous savez écrire un exemple de sérialiseur personnalisé en Kafka (en Java), merci de partager. Merci beaucoup. Merci beaucoup.
Les éléments requis pour écrire un sérialiseur personnalisé sont les suivants:
Encoder
avec un objet spécifié pour le générique VerifiableProperties
est requisetoBytes(...)
en s'assurant qu'un tableau d'octets est retournéProducerConfig
Comme vous l'avez noté dans votre question, Kafka fournit un moyen de déclarer un sérialiseur spécifique pour un producteur. La classe de sérialiseur est définie dans une instance ProducerConfig
et cette instance est utilisée pour construire la classe Producer
souhaitée.
Si vous suivez Exemple de producteur de Kafka vous construirez ProducerConfig
via un objet Properties
. Lors de la création de votre fichier de propriétés, assurez-vous d'inclure:
props.put("serializer.class", "path.to.your.CustomSerializer");
Avec le chemin d'accès à la classe que vous souhaitez Kafka à utiliser pour sérialiser les messages avant de les ajouter au journal.
L'écriture d'un sérialiseur personnalisé que Kafka peut interpréter correctement nécessite la mise en œuvre du Encoder[T]
scala classe que Kafka fournit. Implémentation des traits dans Java est bizarre , mais la méthode suivante a fonctionné pour sérialiser JSON dans mon projet:
public class JsonEncoder implements Encoder<Object> {
private static final Logger logger = Logger.getLogger(JsonEncoder.class);
// instantiating ObjectMapper is expensive. In real life, prefer injecting the value.
private static final ObjectMapper objectMapper = new ObjectMapper();
public JsonEncoder(VerifiableProperties verifiableProperties) {
/* This constructor must be present for successful compile. */
}
@Override
public byte[] toBytes(Object object) {
try {
return objectMapper.writeValueAsString(object).getBytes();
} catch (JsonProcessingException e) {
logger.error(String.format("Json processing failed for object: %s", object.getClass().getName()), e);
}
return "".getBytes();
}
}
Votre question donne l'impression que vous utilisez un seul objet (appelons-le CustomMessage
) pour tous les messages ajoutés à votre journal. Si tel est le cas, votre sérialiseur pourrait ressembler davantage à ceci:
package com.project.serializer;
public class CustomMessageEncoder implements Encoder<CustomMessage> {
public CustomMessageEncoder(VerifiableProperties verifiableProperties) {
/* This constructor must be present for successful compile. */
}
@Override
public byte[] toBytes(CustomMessage customMessage) {
return customMessage.toBytes();
}
}
Ce qui laisserait votre configuration de propriété ressembler à ceci:
props.put("serializer.class", "path.to.your.CustomSerializer");
Vous devez implémenter à la fois le codage et le décodeur
public class JsonEncoder implements Encoder<Object> {
private static final Logger LOGGER = Logger.getLogger(JsonEncoder.class);
public JsonEncoder(VerifiableProperties verifiableProperties) {
/* This constructor must be present for successful compile. */
}
@Override
public byte[] toBytes(Object object) {
ObjectMapper objectMapper = new ObjectMapper();
try {
return objectMapper.writeValueAsString(object).getBytes();
} catch (JsonProcessingException e) {
LOGGER.error(String.format("Json processing failed for object: %s", object.getClass().getName()), e);
}
return "".getBytes();
}
}
Le code du décodeur
public class JsonDecoder implements Decoder<Object> {
private static final Logger LOGGER = Logger.getLogger(JsonEncoder.class);
public JsonDecoder(VerifiableProperties verifiableProperties) {
/* This constructor must be present for successful compile. */
}
@Override
public Object fromBytes(byte[] bytes) {
ObjectMapper objectMapper = new ObjectMapper();
try {
return objectMapper.readValue(bytes, Map.class);
} catch (IOException e) {
LOGGER.error(String.format("Json processing failed for object: %s", bytes.toString()), e);
}
return null;
}
}
L'entrée pom
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.4.1.3</version>
</dependency>
Définissez l'encodeur par défaut dans la propriété Kafka
properties.put("serializer.class","kafka.serializer.DefaultEncoder");
Le code d'écriture et de lecture est le suivant
byte[] bytes = encoder.toBytes(map);
KeyedMessage<String, byte[]> message =new KeyedMessage<String, byte[]>(this.topic, bytes);
JsonDecoder decoder = new JsonDecoder(null);
Map map = (Map) decoder.fromBytes(it.next().message());