kafka 配置自定义序列化方式

序列化

  • kafka 需要将消息内容序列化(Serializer)成字节数组才能发送到 Broken节点

  • 消费者需要将字节数组反序列化(Deserializer)为消息内容,然后消费消息。接口定义如下

java 复制代码
public interface Serializer<T> extends Closeable {
    default void configure(Map<String, ?> configs, boolean isKey) {
    }

    byte[] serialize(String var1, T var2);

    default byte[] serialize(String topic, Headers headers, T data) {
        return this.serialize(topic, data);
    }

    default void close() {
    }
}
java 复制代码
public interface Deserializer<T> extends Closeable {
    default void configure(Map<String, ?> configs, boolean isKey) {
    }

    T deserialize(String var1, byte[] var2);

    default T deserialize(String topic, Headers headers, byte[] data) {
        return this.deserialize(topic, data);
    }

    default void close() {
    }
}

常用序列化器

kafka 内置了许多实现如 StringSerializer、IntegerSerializer、DoubleSerializer 等。

生产者与消费者 选择的序列化与反序列化要匹配才能正常解析

自定义序列化器

自定义序列化器 只需要实现对应的 Serializer,UserDeserializer

比如有一个 User 类

java 复制代码
@Data
@NoArgsConstructor
@AllArgsConstructor
public class User {
    private Long id;
    private String userName;
}

UserSerializer

java 复制代码
public class UserSerializer implements Serializer<User> {

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

    @Override
    public byte[] serialize(String s, User user) {
        return JSON.toJSONBytes(user);
    }

    @Override
    public void close() {

    }
}
java 复制代码
public class UserDeserializer implements Deserializer<User> {
    @Override
    public User deserialize(String s, byte[] bytes) {
        return JSON.parseObject(bytes,User.class);
    }
}

生产者与消费者配置

java 复制代码
props.put(ConsumerConfig.KEY_DESERIALIZER_CLASS_CONFIG, IntegerDeserializer.class);
props.put(ConsumerConfig.VALUE_DESERIALIZER_CLASS_CONFIG, UserDeserializer.class);
...
props.put(ProducerConfig.KEY_SERIALIZER_CLASS_CONFIG, IntegerSerializer.class);
props.put(ProducerConfig.VALUE_SERIALIZER_CLASS_CONFIG, UserSerializer.class);

上面我们配置了 User 相关的序列化,但是实际上项目发送的消息内容肯定不止 User 这一种,我们需要针对不同类型指定不同的序列化方式

DelegatingByTypeSerializer

从 2.8 开始新增了DelegatingByTypeSerializer完美解决了上面问题用法如下,

java 复制代码
    @Bean
    public ProducerFactory producerFactory() {
        Map<Class<?>, Serializer> delegates = new HashMap<>();
        delegates.put(byte[].class, new ByteArraySerializer());
        delegates.put(Bytes.class, new BytesSerializer());
        delegates.put(String.class, new StringSerializer());
        delegates.put(User.class, new UserSerializer());
        return new DefaultKafkaProducerFactory<>(produceConfigs(),
                new StringSerializer(), new DelegatingByTypeSerializer(delegates));
    }

消费者序列化可以在 @KafkaListener 指定

完整配置

确保kafka-clients版本在2.8以上

kafka 配置类

java 复制代码
@Configuration
@EnableKafka
public class KafkaConfig {

    private Map<String, Object> produceConfigs() {
        Map<String, Object> configMap = new HashMap<>();
        configMap.put(ProducerConfig.BOOTSTRAP_SERVERS_CONFIG,
                "ip:9092");
        configMap.put(ProducerConfig.KEY_SERIALIZER_CLASS_CONFIG, IntegerSerializer.class);
        return configMap;
    }

    @Bean
    public ProducerFactory producerFactory() {
        Map<Class<?>, Serializer> delegates = new HashMap<>();
        delegates.put(byte[].class, new ByteArraySerializer());
        delegates.put(Bytes.class, new BytesSerializer());
        delegates.put(String.class, new StringSerializer());
        delegates.put(User.class, new UserSerializer());
        return new DefaultKafkaProducerFactory<>(produceConfigs(),
                new StringSerializer(), new DelegatingByTypeSerializer(delegates));
    }

    @Bean
    public KafkaTemplate kafkaTemplate() {
        return new KafkaTemplate(producerFactory());
    }

    private Map<String, Object> consumerConfigs() {
        Map<String, Object> configMap = new HashMap<>();
        configMap.put(ConsumerConfig.BOOTSTRAP_SERVERS_CONFIG,
                "ip:9092");
        configMap.put(ConsumerConfig.KEY_DESERIALIZER_CLASS_CONFIG,
                IntegerDeserializer.class);
        configMap.put(ConsumerConfig.VALUE_DESERIALIZER_CLASS_CONFIG,
                StringDeserializer.class);
        configMap.put(ConsumerConfig.GROUP_ID_CONFIG, "groupTest");

        return configMap;
    }


}

消费者 @KafkaListener 注解可以指定序列化器

java 复制代码
 @KafkaListener(topics = "test")
    public void processMessage(final ConsumerRecord<String,User> record) {
        System.out.println("processMessage:" + JSON.toJSONString(record.value()));
    }

    @KafkaListener(topics = "topic2",properties = "value-deserializer:org.apache.kafka.common.serialization.StringDeserializer")
    public void processMessage(String content) {
        System.out.println("processMessage:" + content);

    }

发送消息代码

java 复制代码
for (int i = 0; i < 100; i++) {
    messageProduce.sendMessage(new User(Long.valueOf(i), "zhangsan" + i));
    messageProduce.sendMessage2("hello world" + i);
}

结果验证

消息被正常消费

总结

本文主要介绍了自定义序列化方式,以及为不同类型指定不同的序列化实现方式。

由于篇幅有限,文中只包含核心配置和重要代码,部分代码未贴出,可留言交流学习。

相关推荐
nvd116 小时前
深入剖析:GCP Pub/Sub 与 Apache Kafka 对消息处理延迟与消费者卡死的处理机制异同
分布式·kafka·apache
笔墨登场说说1 天前
centos 8 使用 kafka_2.13-4.3.1.tgz 安装kafka
linux·kafka·centos
guo_wen_qiang1 天前
kafka一直restarting,报错InconsistentClusterIdException
分布式·kafka
今年下半年1 天前
【消息队列】Spring Boot 集成 Kafka 消息队列:确保消费完成(手动提交偏移量+幂等判断+失败重试机制)
spring boot·kafka·幂等·失败重试
此时不提桶,更待何时2 天前
06-14-A-Kafka集群运维与迁移实战详解
运维·kafka
yumgpkpm2 天前
Acceldata ODP(Open Data Platform)3.3.6.4(RHEL9)保姆级完整安装手册
大数据·人工智能·hive·hadoop·kafka·hbase·cloudera
用户1494484813202 天前
Raft 为什么取代了 Paxos?从 DLedger 和 KRaft 的技术选型聊起
kafka·raft
此时不提桶,更待何时2 天前
06-16-B-Kafka面试与生产事故实战
分布式·面试·kafka
阿里云云原生2 天前
Kafka 不止于消息:阿里云发布面向 AI 的流算湖一体化实时数据平台
kafka
龙腾-虎跃3 天前
Docker 一键启动服务合集:Redis、MySQL、Kafka、MinIO、Prometheus 等(网盘转存防失效)
redis·mysql·docker·kafka·prometheus·小龙虾·miniio