在Kafka Streams应用中,Serde(Serializer/Deserializer)负责消息的序列化与反序列化工作,确保数据在生产者、broker和消费者之间正确传输和解析。有时候,Kafka Streams提供的内置Serde可能无法满足特定数据类型的需求,此时需要自定义Serde。以下是一个自定义Serde的实战示例,假设我们有一个自定义的交易数据类Transaction
:
public class Transaction {
private String accountId;
private double amount;
private long timestamp;
// 构造函数、getter、setter与equals/hashCode/toString方法省略...
}
我们需要创建一个自定义的Serde,用于处理这种类型的数据。
TransactionSerde.java
import org.apache.kafka.common.serialization.Deserializer;
import org.apache.kafka.common.serialization.Serde;
import org.apache.kafka.common.serialization.Serializer;
import java.util.Map;
public class TransactionSerde implements Serde<Transaction> {
private final Serializer<Transaction> serializer;
private final Deserializer<Transaction> deserializer;
public TransactionSerde() {
this.serializer = new TransactionSerializer();
this.deserializer = new TransactionDeserializer();
}
@Override
public void configure(Map<String, ?> configs, boolean isKey) {
serializer.configure(configs, isKey);
deserializer.configure(configs, isKey);
}
@Override
public void close() {
serializer.close();
deserializer.close();
}
@Override
public Serializer<Transaction> serializer() {
return serializer;
}
@Override
public Deserializer<Transaction> deserializer() {
return deserializer;
}
// 自定义的序列化器
public static class TransactionSerializer implements Serializer<Transaction> {
@Override
public byte[] serialize(String topic, Transaction data) {
if (data == null) {
return null;
}
try {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(baos);
oos.writeObject(data);
return baos.toByteArray();
} catch (IOException e) {
throw new SerializationException("Error serializing Transaction to bytes", e);
}
}
@Override
public void close() {
// 可以在这里添加关闭资源的操作,如关闭流等
}
}
// 自定义的反序列化器
public static class TransactionDeserializer implements Deserializer<Transaction> {
@Override
public Transaction deserialize(String topic, byte[] data) {
if (data == null) {
return null;
}
try {
ByteArrayInputStream bais = new ByteArrayInputStream(data);
ObjectInputStream ois = new ObjectInputStream(bais);
return (Transaction) ois.readObject();
} catch (IOException | ClassNotFoundException e) {
throw new SerializationException("Error deserializing bytes to Transaction", e);
}
}
@Override
public void close() {
// 可以在这里添加关闭资源的操作,如关闭流等
}
}
}
使用自定义Serde的Kafka Streams示例
import org.apache.kafka.common.serialization.Serdes;
import org.apache.kafka.streams.KafkaStreams;
import org.apache.kafka.streams.StreamsBuilder;
import org.apache.kafka.streams.StreamsConfig;
import org.apache.kafka.streams.kstream.KStream;
import org.apache.kafka.streams.kstream.Printed;
import java.util.Properties;
public class TransactionProcessingDemo {
public static void main(String[] args) {
Properties streamsConfig = new Properties();
streamsConfig.put(StreamsConfig.APPLICATION_ID_CONFIG, "transaction-processing");
streamsConfig.put(StreamsConfig.BOOTSTRAP_SERVERS_CONFIG, "localhost:9092");
streamsConfig.put(StreamsConfig.DEFAULT_KEY_SERDE_CLASS_CONFIG, Serdes.String().getClass());
streamsConfig.put(StreamsConfig.DEFAULT_VALUE_SERDE_CLASS_CONFIG, TransactionSerde.class);
StreamsBuilder builder = new StreamsBuilder();
// 使用自定义Serde的KStream
KStream<String, Transaction> transactionStream = builder.stream("transactions", Consumed.with(Serdes.String(), new TransactionSerde()));
// 打印交易数据到控制台
transactionStream.print(Printed.toSysOut());
KafkaStreams streams = new KafkaStreams(builder.build(), streamsConfig);
streams.start();
// 在程序退出前,优雅地关闭Kafka Streams应用
Runtime.getRuntime().addShutdownHook(new Thread(streams::close));
}
}
示例解析:
-
自定义Serde:创建
TransactionSerde
类,实现Serde<Transaction>
接口。内部包含两个嵌套类:TransactionSerializer
和TransactionDeserializer
,分别实现序列化和反序列化逻辑。这里使用了Java的ObjectOutputStream
和ObjectInputStream
进行对象的序列化和反序列化。 -
配置自定义Serde:在Kafka Streams应用的配置中,设置
DEFAULT_VALUE_SERDE_CLASS_CONFIG
为自定义的TransactionSerde
类。 -
使用自定义Serde的KStream:在创建KStream时,指定键的Serde为
Serdes.String()
,值的Serde为new TransactionSerde()
。这样,Kafka Streams就会使用自定义的Serde处理Transaction
类型的数据。 -
运行示例:创建Kafka Streams拓扑,打印交易数据到控制台,并启动应用。在程序退出前,注册一个shutdown hook以优雅地关闭Kafka Streams应用。
通过上述实战示例,我们展示了如何创建自定义的Serde类来处理自定义数据类型,并在Kafka Streams应用中正确配置和使用自定义Serde。实际应用中,可以根据需要调整序列化和反序列化逻辑,以适应不同的数据格式和传输需求。注意,序列化和反序列化过程中应处理好异常,确保数据的完整性和一致性。