当生产者以List <object>发送时,Kafka消费者以不同的格式接收消息

时间:2018-12-07 08:02:43

标签: apache-kafka kafka-consumer-api kafka-producer-api spring-kafka

I am sending `List<Object>` from Kafka Producer to a topic. A consumer which listens to the topic receives the message but in a different format(i.e. `List<LinkedHashMap>` instead of `List<Object>`)

Any idea on how to receive the List<Object> messages in the consumer?I am sending `List<foo>`. But in the Consumer, data comes as `List<LinkedHashMap>`      

只需更改以下示例作为列表         https://memorynotfound.com/spring-kafka-json-serializer-deserializer-example/ 从链接中可以找到发件人和侦听器。唯一的变化是发件人将使用对象而不是Foo。

public class SpringKafkaApplication implements CommandLineRunner {
        public static void main(String[] args) {
                SpringApplication.run(SpringKafkaApplication.class, args);
            }

            @Autowired
            private FooSender sender;

            @Override
            public void run(String... strings) throws Exception {
            List<Foo> f = new ArrayList<>();

        f.add(new Foo("Spring Kafka", "sending and receiving JSON messages"))
        f.add(new Foo("Spring Kafka1", "sending and receiving11"))
                sender.send(f);
            }
        }

1 个答案:

答案 0 :(得分:1)

不要在注释中添加代码;很难阅读-而是编辑问题。

您使用的是什么版本的spring-kafka?

您至少需要2.1.x和一个Kafka代理> = 0.11,以便可以在标头中传达类型信息。 See here

在早期版本中,必须将解串器配置为目标类型。

编辑

我看到了问题;由于类型擦除,序列化程序不知道容器(列表)的内容类型,因此它不会尝试对集合进行内部检查以找到类型。

虽然我们可以针对集合之类的简单情况解决此问题,但更复杂的对象(例如地图)将是一个挑战。

数组而不是列表可能会起作用。

同时,您可以改用消息转换器,在此我们使用侦听器的参数类型来确定所需的类型。这是一个示例:

@SpringBootApplication
public class So53665459Application2 {

    public static void main(String[] args) {
        SpringApplication.run(So53665459Application2.class, args);
    }

    @Bean
    public NewTopic topic() {
        return new NewTopic("so53665459", 1, (short) 1);
    }

    @Bean
    public MessageConverter converter() {
        return new StringJsonMessageConverter();
    }

    @KafkaListener(id = "so53665459", topics = "so53665459")
    public void listen(List<Foo1> foos) {
        System.out.println(foos);
    }

    @Bean
    public ApplicationRunner runner(KafkaTemplate<String, List<Object>> template) {
        return args -> template.send("so53665459", Collections.singletonList(new Foo1("baz1")));
    }

    public static class Foo1 {

        private String bar;

        public Foo1() {
            super();
        }

        Foo1(String bar) {
            this.bar = bar;
        }

        public String getBar() {
            return this.bar;
        }

        public void setBar(String bar) {
            this.bar = bar;
        }

        @Override
        public String toString() {
            return "Foo1 [bar=" + this.bar + "]";
        }

    }

}

spring.kafka.producer.value-serializer=org.springframework.kafka.support.serializer.JsonSerializer
#spring.kafka.consumer.value-deserializer= boot's default StringDeserializer
spring.kafka.consumer.enable-auto-commit=false
spring.kafka.consumer.auto-offset-reset=earliest

[Foo1 [bar=baz1]]

或者,您可以对序列化器进行子类化,以使用适当的类型设置标头,以帮助反序列化器。