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);
}

结果验证

消息被正常消费

总结

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

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

相关推荐
qq_5470261797 小时前
Kafka 常见问题
kafka
core5127 小时前
flink sink kafka
flink·kafka·sink
飞来又飞去8 小时前
kafka sasl和acl之间的关系
分布式·kafka
张伯毅14 小时前
Flink SQL 支持 kafka 开启 kerberos 权限控制.
sql·flink·kafka
darkdragonking17 小时前
OpenEuler 22.03 不依赖zookeeper安装 kafka 3.3.2集群
kafka
saynaihe1 天前
安全地使用 Docker 和 Systemctl 部署 Kafka 的综合指南
运维·安全·docker·容器·kafka
隔着天花板看星星1 天前
Spark-Streaming集成Kafka
大数据·分布式·中间件·spark·kafka
太阳伞下的阿呆2 天前
kafka常用命令(持续更新)
分布式·kafka
BUTCHER52 天前
Kafka安装篇
分布式·kafka
若雨叶2 天前
Kafka实现监听多个topic
分布式·kafka