Spring Kafka消息反序列化失败,因为content-type设置为application / json

时间:2019-07-15 09:12:34

标签: apache-kafka spring-kafka spring-cloud-stream

我正在向Kafka发送消息,如下所示:

private KafkaTemplate<String, MyMessage > kafkaTemplate;

public void sendMessage(MyMessage data) {

    Message<MyMessage > message = MessageBuilder
            .withPayload(data)
            .setHeader(KafkaHeaders.TOPIC,topic)
            .setHeader(KafkaHeaders.MESSAGE_KEY,data.getKey())
            .build();
    kafkaTemplate.send(message);

我对MyMessage有自己的自定义解串器,键是一个简单的String

我正在尝试按以下方式处理消息:

@StreamListener
    public void process(@Input("input") KStream<String,MyMessage> myStream){
            final Serde<String> stringSerde = Serdes.String();
            final MyMessageSerde myMessageSerde = new MyMessageSerde();
            myStream
                    .groupBy((key,value)-> value.getObjectKey(), Serialized.with(stringSerde,myMessageSerde))
                    .aggregate(ArrayList::new,
                            (newKey,val,agg) -> {
                                agg.add(val);
                                return agg;
                            },
                            Materialized.<String, ArrayList<MyMessage>, KeyValueStore<Bytes, byte[]>>as("object-keys")
                                    .withKeySerde(stringSerde)
                                    .withValueSerde(new ArrayListSerde(myMessageSerde)));

    ...
    interface MyStreamProcessor {
        @Input("input")
        KStream<?, ?> input();
    }

这失败,发生反序列化错误,调试后我看到原因是消息的内容类型标头设置为application / json,因此它正尝试将消息反序列化为JSON。如何设置内容类型标头,如何覆盖它?我不是以JSON的形式发送消息,而是像常规的Kafka消息那样以byte []的形式发送消息,因此我希望使用自定义的de / serializer

甚至更陌生的是,如果我将其更改为KTable,则可以正常工作。

@StreamListener
public void process(@Input("input") KTable<String,MyMessage> myTable){
        final Serde<String> stringSerde = Serdes.String();
        final MyMessageSerde myMessageSerde = new MyMessageSerde();
        KStream<String,MyMessage> myStream = myTable.toStream();
        myStream
                .groupBy((key,value)-> value.getObjectKey(), Serialized.with(stringSerde,myMessageSerde))
                .aggregate(ArrayList::new,
                        (newKey,val,agg) -> {
                            agg.add(val);
                            return agg;
                        },
                        Materialized.<String, ArrayList<MyMessage>, KeyValueStore<Bytes, byte[]>>as("object-keys")
                                .withKeySerde(stringSerde)
                                .withValueSerde(new ArrayListSerde(myMessageSerde)));

...
interface MyStreamProcessor {
    @Input("input")
    KTable<?, ?> input();
}

为什么使用KTable可以正确反序列化消息? KStream和KTable之间的行为有什么区别?

2 个答案:

答案 0 :(得分:0)

之所以起作用,是因为您在.group方法中指定了自定义(反)序列化。 看看文档的thisthis部分,看看如何指定自定义值Serde。

答案 1 :(得分:0)

我通过执行以下操作使它起作用:

  1. 在我的application.yml文件中设置输入内容类型标头,如下所示: spring.cloud.stream.bindings.input.content-type: application/mymessage

  2. 创建一个CustomMessageConverter,它扩展AbstractMessageConverter以便从字节[]转换为MyMessage。它还定义了新的MimeType

public MyMappingConverter() { super(new MimeType("application", "mymessage")); }

  1. 创建一个MessageConverter bean

@Bean @StreamMessageConverter public MessageConverter myMessageConverter() { return new MyMessageConverter(); }

我仍然不知道为什么我必须对KStream而不是对KTable进行所有这些操作,如果有人可以解释说,将不胜感激。