Spring Kafka @SendTo不发送标题

时间:2019-04-10 22:37:17

标签: spring apache-kafka spring-kafka spring-kafka-test

我正在使用ReplyingKafkaTemplate向Kafka发送消息,并且正在与kafka_correlationId发送消息。但是,当它到达我的@KafkaListener方法并将其转发给回复主题时,标头会丢失。

如何保存kafka标头?

这是我的方法签名:

@KafkaListener(topics = "input")
@SendTo("reply")
public List<CustomOutput> consume(List<CustomInput> inputs) {
  ... /* some processing */
  return outputs;
}

我已经创建了ProducerInterceptor,所以我可以看到正在从ReplyingKafkaTemplate以及从@SendTo批注发送的标题。因此,另一个奇怪的事情是ReplyingKafkaTemplate没有在邮件中添加记录的kafka_replyTopic标头。

ReplyingKafkaTemplate的配置方式如下:

@Bean
public KafkaMessageListenerContainer<Object, Object> replyContainer(ConsumerFactory<Object, Object> cf) {
  ContainerProperties containerProperties = new ContainerProperties(requestReplyTopic);
  return new KafkaMessageListenerContainer<>(cf, containerProperties);
}

@Bean
public ReplyingKafkaTemplate<Object, Object, Object> replyingKafkaTemplate(ProducerFactory<Object, Object> pf, KafkaMessageListenerContainer<Object, Object> container) {
  return new ReplyingKafkaTemplate<>(pf, container);
}

我不确定这是否相关,但是我也添加了 Spring Cloud Sleuth 作为依赖项,并且在发送消息时,span / trace标头就存在了,但是转发消息时会生成新消息。

1 个答案:

答案 0 :(得分:1)

默认情况下,请求消息中的任意标头不会复制到回复消息中,而只会复制到kafka_correlationId

从2.2版开始,您可以配置ReplyHeadersConfigurer,调用该ReplyHeadersConfigurer以确定应复制哪些标头。

请参见the documentation

  

从2.2版开始,您可以将Message<?>添加到侦听器容器工厂。请咨询以确定您要在回复消息中设置的标头。

编辑

顺便说一句,在2.2中,如果没有标题,RKT会自动设置replyTo。

使用2.1.x可以完成此操作,但这有点复杂,您必须自己做一些工作。关键是接收和回复@KafkaListener(id = "so55622224", topics = "so55622224") @SendTo("dummy.we.use.the.header.instead") public Message<?> listen(Message<String> in) { System.out.println(in); Headers nativeHeaders = in.getHeaders().get(KafkaHeaders.NATIVE_HEADERS, Headers.class); byte[] replyTo = nativeHeaders.lastHeader(KafkaHeaders.REPLY_TOPIC).value(); byte[] correlation = nativeHeaders.lastHeader(KafkaHeaders.CORRELATION_ID).value(); return MessageBuilder.withPayload(in.getPayload().toUpperCase()) .setHeader("myHeader", nativeHeaders.lastHeader("myHeader").value()) .setHeader(KafkaHeaders.CORRELATION_ID, correlation) .setHeader(KafkaHeaders.TOPIC, replyTo) .build(); } // This is used to send the reply - needs a header mapper @Bean public KafkaTemplate<?, ?> kafkaTemplate(ProducerFactory<Object, Object> kafkaProducerFactory) { KafkaTemplate<Object, Object> kafkaTemplate = new KafkaTemplate<>(kafkaProducerFactory); MessagingMessageConverter messageConverter = new MessagingMessageConverter(); messageConverter.setHeaderMapper(new SimpleKafkaHeaderMapper("*")); // map all byte[] headers kafkaTemplate.setMessageConverter(messageConverter); return kafkaTemplate; } @Bean public ApplicationRunner runner(ReplyingKafkaTemplate<String, String, String> template) { return args -> { Headers headers = new RecordHeaders(); headers.add(new RecordHeader("myHeader", "myHeaderValue".getBytes())); headers.add(new RecordHeader(KafkaHeaders.REPLY_TOPIC, "so55622224.replies".getBytes())); // automatic in 2.2 ProducerRecord<String, String> record = new ProducerRecord<>("so55622224", null, null, "foo", headers); RequestReplyFuture<String, String, String> future = template.sendAndReceive(record); ConsumerRecord<String, String> reply = future.get(); System.out.println("Reply: " + reply.value() + " myHeader=" + new String(reply.headers().lastHeader("myHeader").value())); }; } ...

frozenset