Spring Kafka 2.2类型映射类加载器不匹配

时间:2018-11-30 14:59:50

标签: spring spring-kafka

我正在尝试使用Spring Kafka 2.2中引入的新类型映射功能:

向下滚动到“映射类型”:
https://docs.spring.io/spring-kafka/reference/htmlsingle/#serdes

在生产者端,我注册了一个映射,如下所示:

senderProps.put(ProducerConfig.VALUE_SERIALIZER_CLASS_CONFIG, JsonSerializer.class);
senderProps.put(JsonSerializer.TYPE_MAPPINGS, "foo:com.myfoo.Foo");

关于消费者,如下:

consumerProps.put(ConsumerConfig.VALUE_DESERIALIZER_CLASS_CONFIG, JsonDeserializer.class);
consumerProps.put(JsonDeSerializer.TYPE_MAPPINGS, "foo:com.yourfoo.Foo");

但是,在将事件发送到com.myfoo.Foo类的生产者端的Kafka时,添加到记录中的classId标头是com.myfoo.Foo而不是foo。因此,在消费者方面,由于com.myfoo.Foo未知,因此无法反序列化。

在spring-kafka中,我将问题缩小到此方法:

https://github.com/spring-projects/spring-kafka/blob/master/spring-kafka/src/main/java/org/springframework/kafka/support/converter/AbstractJavaTypeMapper.java#L142

protected void addHeader(Headers headers, String headerName, Class<?> clazz) {
    if (this.classIdMapping.containsKey(clazz)) {
        headers.add(new RecordHeader(headerName, this.classIdMapping.get(clazz)));
    }
    else {
        headers.add(new RecordHeader(headerName, clazz.getName().getBytes(StandardCharsets.UTF_8)));
    }
}

在通过执行卡夫卡记录的序列化进行调试时,执行实际上转到else分支,而据我所知,它实际上应该转到if分支并添加foo作为标题。而是将com.myfoo.Foo添加到标题中。

罪魁祸首似乎与类加载器不匹配有关,但我不确定这是否是错误或我最后做的愚蠢。

基本上,classIdMapping映射已正确填充了com.myfoo.Foo作为键,而foo的UTF-8 byte []表示形式是对应的值。

但是,在if chec期间,clazz参数是一个类,它是由与classIdMapping映射中存储的类不同的类装载器装载的,因此哈希码是不同的,并且转到else分支

这实际上是String-Kafka方面的错误,还是我配置错误?

谢谢

1 个答案:

答案 0 :(得分:2)

这确实看起来像我们实施中的遗漏。请为Apache Kafka项目的Spring提出一个问题:https://github.com/spring-projects/spring-kafka。我们的想法是不使用Class<?>进行映射,而是使用其完全合格的类名

似乎您的应用程序是多类加载器,例如它是Web。然后,Apache Kafka Client将senderProps.put(ProducerConfig.VALUE_SERIALIZER_CLASS_CONFIG, JsonSerializer.class);加载到其ClassLoader中,而其他所有事情都由应用程序上下文ClassLoader完成。

作为一种解决方法,在解决此问题的同时,建议使用DefaultKafkaProducerFactory配置及其setValueSerializer()来填充JsonSerializer bean参考。这样,您需要通过其setTypeMapper()填充类映射,因此需要在setIdClassMapping()上填充DefaultJackson2JavaTypeMapper