kafka自定义序列化反序列化

  • 0. 问题
  • 1. 原因分析
  • 2. 解决方法
  • 3. 结果测试

0. 问题

最近在学习kafka的时候碰到一个问题,当我尝试使用kafka发生一个pojo对象时,使用如下配置的时候,发现代码报错了,是类型匹配错误:
application.yuml配置如下

###ThymeLeaf配置
spring:
  thymeleaf:
    #模板的模式,支持 HTML, XML TEXT JAVASCRIPT
    mode: HTML5
    #编码 可不用配置
    encoding: UTF-8
    #内容类别,可不用配置
    content-type: text/html
    #开发配置为false,避免修改模板还要重启服务器
    cache: false
    #配置模板路径,默认是templates,可以不用配置
    prefix: classpath:/templates/
    suffix: .html
    enabled: true
    #国际化
  messages:
    basename: i18n.login

    ###########【Kafka集群】###########
  kafka:
    bootstrap-servers: 192.168.160.131:9092
    ###########【初始化生产者配置】###########
    producer:
      # 重试次数
      retries: 0
      # 应答级别:多少个分区副本备份完成时向生产者发送ack确认(可选0、1、all/-1)
      acks: 1
      # 批量大小
      batch-size: 16384
      # 生产端缓冲区大小
      buffer-memory: 33554432
      # Kafka提供的序列化和反序列化类
      key-serializer: org.apache.kafka.common.serialization.StringSerializer
      value-serializer: org.apache.kafka.common.serialization.StringSerializer

    ###########【初始化消费者配置】###########
    consumer:
      # 是否自动提交offset
      enable-auto-commit: true
      # 提交offset延时(接收到消息后多久提交offset)
      auto-commit-interval: 1000
      # 当kafka中没有初始offset或offset超出范围时将自动重置offset
      # earliest:重置为分区中最小的offset;
      # latest:重置为分区中最新的offset(消费分区中新产生的数据);
      # none:只要有一个分区不存在已提交的offset,就抛出异常;
      auto-offset-reset: latest
      # Kafka提供的序列化和反序列化类
      key-deserializer: org.apache.kafka.common.serialization.StringDeserializer
      value-deserializer: org.apache.kafka.common.serialization.StringDeserializer
      # 默认的消费组ID
      group-id: defaultConsumerGroup

    # 消费端监听的topic不存在时,项目启动会报错(关掉)
    listener:
      missing-topics-fatal: false

当我传输一个pojo类时报错:

2021-05-30 15:31:08.159  INFO 6856 --- [nio-8080-exec-2] o.a.kafka.common.utils.AppInfoParser     : Kafka version: 2.6.0
2021-05-30 15:31:08.159  INFO 6856 --- [nio-8080-exec-2] o.a.kafka.common.utils.AppInfoParser     : Kafka commitId: 62abe01bee039651
2021-05-30 15:31:08.159  INFO 6856 --- [nio-8080-exec-2] o.a.kafka.common.utils.AppInfoParser     : Kafka startTimeMs: 1622359868159
2021-05-30 15:31:08.166  INFO 6856 --- [ad | producer-1] org.apache.kafka.clients.Metadata        : [Producer clientId=producer-1] Cluster ID: Hc_Yc5NaSh6xZSiNbs5Vog
2021-05-30 15:31:08.188 ERROR 6856 --- [nio-8080-exec-2] o.a.c.c.C.[.[.[/].[dispatcherServlet]    : Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; nested exception is org.apache.kafka.common.errors.SerializationException: Can't convert value of class club.jming.pojo.Employee to class org.apache.kafka.common.serialization.StringSerializer specified in value.serializer] with root cause

java.lang.ClassCastException: class club.jming.pojo.Employee cannot be cast to class java.lang.String (club.jming.pojo.Employee is in unnamed module of loader 'app'; java.lang.String is in module java.base of loader 'bootstrap')

1. 原因分析

这是由于配置文件(默认也是)使用的序列化和反序列化方法为:

# Kafka提供的序列化和反序列化类
key-serializer: org.apache.kafka.common.serialization.StringSerializer
value-serializer: org.apache.kafka.common.serialization.StringSerializer
# Kafka提供的序列化和反序列化类
key-deserializer: org.apache.kafka.common.serialization.StringDeserializer
value-deserializer: org.apache.kafka.common.serialization.StringDeserializer

使用的是字符串序列和反序列化方法,但我们传送的是pojo类,所以会报错ClassCastException

java.lang.ClassCastException: class club.jming.pojo.Employee cannot be cast to class java.lang.String (club.jming.pojo.Employee is in unnamed module of loader 'app'; java.lang.String is in module java.base of loader 'bootstrap')

2. 解决方法

自定义序列化和反序列化类,并在配置文件中指定,注:这里使用了fastjson解析json和序列化json。
自定义的序列化类:

/**
 * 自定义序列化
 * @author 78289
 */
public class JsonSerializer implements Serializer<Object> {

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

自定义的反序列化类:

/**
 * 自定义反序列化类
 * @author 78289
 */
public class JsonDeserializer implements Deserializer<Object> {
    @Override
    public Object deserialize(String topic, byte[] bytes) {
        return JSON.parseObject(bytes,Object.class);
    }
}

修改后的配置文件:

###ThymeLeaf配置
spring:
  thymeleaf:
    #模板的模式,支持 HTML, XML TEXT JAVASCRIPT
    mode: HTML5
    #编码 可不用配置
    encoding: UTF-8
    #内容类别,可不用配置
    content-type: text/html
    #开发配置为false,避免修改模板还要重启服务器
    cache: false
    #配置模板路径,默认是templates,可以不用配置
    prefix: classpath:/templates/
    suffix: .html
    enabled: true
    #国际化
  messages:
    basename: i18n.login

    ###########【Kafka集群】###########
  kafka:
    bootstrap-servers: 192.168.160.131:9092
    ###########【初始化生产者配置】###########
    producer:
      # 重试次数
      retries: 0
      # 应答级别:多少个分区副本备份完成时向生产者发送ack确认(可选0、1、all/-1)
      acks: 1
      # 批量大小
      batch-size: 16384
      # 生产端缓冲区大小
      buffer-memory: 33554432
      # Kafka提供的序列化和反序列化类
      key-serializer: org.apache.kafka.common.serialization.StringSerializer
      value-serializer: club.jming.utils.JsonSerializer

    ###########【初始化消费者配置】###########
    consumer:
      # 是否自动提交offset
      enable-auto-commit: true
      # 提交offset延时(接收到消息后多久提交offset)
      auto-commit-interval: 1000
      # 当kafka中没有初始offset或offset超出范围时将自动重置offset
      # earliest:重置为分区中最小的offset;
      # latest:重置为分区中最新的offset(消费分区中新产生的数据);
      # none:只要有一个分区不存在已提交的offset,就抛出异常;
      auto-offset-reset: latest
      # Kafka提供的序列化和反序列化类
      key-deserializer: org.apache.kafka.common.serialization.StringDeserializer
      value-deserializer: club.jming.utils.JsonDeserializer
      # 默认的消费组ID
      group-id: defaultConsumerGroup

    # 消费端监听的topic不存在时,项目启动会报错(关掉)
    listener:
      missing-topics-fatal: false

3. 结果测试

2021-05-30 15:37:44.886  INFO 8828 --- [nio-8080-exec-2] o.a.kafka.common.utils.AppInfoParser     : Kafka version: 2.6.0
2021-05-30 15:37:44.886  INFO 8828 --- [nio-8080-exec-2] o.a.kafka.common.utils.AppInfoParser     : Kafka commitId: 62abe01bee039651
2021-05-30 15:37:44.886  INFO 8828 --- [nio-8080-exec-2] o.a.kafka.common.utils.AppInfoParser     : Kafka startTimeMs: 1622360264886
2021-05-30 15:37:44.892  INFO 8828 --- [ad | producer-1] org.apache.kafka.clients.Metadata        : [Producer clientId=producer-1] Cluster ID: Hc_Yc5NaSh6xZSiNbs5Vog
简单消费-0-topic1-hello_kafka
简单消费-0-topic1-{"gender":1,"birth":1622360264930,"id":1,"email":"782893110@qq.com"}

传输成功!