Spring Kafka@SendTo不发送头

Spring Kafka@SendTo不发送头,spring,apache-kafka,spring-kafka,spring-kafka-test,Spring,Apache Kafka,Spring Kafka,Spring Kafka Test,我正在使用回复卡夫卡模板向卡夫卡发送消息,它正在使用卡夫卡关联ID发送消息。但是,当它点击我的@KafkaListener方法并将其转发到回复主题时,标题将丢失 如何保存卡夫卡标题? 这是我的方法签名: @KafkaListener(topics = "input") @SendTo("reply") public List<CustomOutput> consume(List<CustomInput> inputs) { ... /* some processing

我正在使用
回复卡夫卡模板
向卡夫卡发送消息,它正在使用
卡夫卡关联ID
发送消息。但是,当它点击我的
@KafkaListener
方法并将其转发到回复主题时,标题将丢失

如何保存卡夫卡标题?

这是我的方法签名:

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

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

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

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

从2.2版开始,您可以向侦听器容器工厂添加
ReplyHeadersConfigurer
。这将用于确定要在回复消息中设置的标题

编辑

顺便说一句,在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()));
    };
}
@KafkaListener(id=“so55622224”,topics=“so55622224”)
@SendTo(“dummy.we.use.the.header.instead”)
公共消息侦听(消息输入){
系统输出打印项次(输入);
Headers nativeHeaders=in.getHeaders().get(KafkaHeaders.NATIVE_Headers,Headers.class);
字节[]replyTo=nativeHeaders.lastHeader(KafkaHeaders.REPLY_TOPIC).value();
byte[]correlation=nativeHeaders.lastHeader(KafkaHeaders.correlation_ID).value();
返回MessageBuilder.withPayload(在.getPayload().toUpperCase()中)
.setHeader(“myHeader”,nativeHeaders.lastHeader(“myHeader”).value()
.setHeader(KafkaHeaders.CORRELATION\u ID,CORRELATION)
.setHeader(KafkaHeaders.TOPIC,replyTo)
.build();
}
//这用于发送回复-需要标头映射器
@豆子
公共卡夫卡模板卡夫卡模板(生产工厂卡夫卡生产工厂){
KafkaTemplate KafkaTemplate=新的KafkaTemplate(kafkaProducerFactory);
MessagingMessageConverter messageConverter=新MessagingMessageConverter();
messageConverter.setHeaderMapper(新的SimpleKafkaHeaderMapper(“*”);//映射所有字节[]头
kafkaTemplate.setMessageConverter(messageConverter);
返回卡夫卡模板;
}
@豆子
公共应用程序运行程序(回复KafkatTemplate模板){
返回参数->{
Headers=newrecordheaders();
添加(新记录头(“myHeader”,“myHeaderValue”.getBytes());
headers.add(新记录头(KafkaHeaders.REPLY_主题“so55622224.reples”.getBytes());//在2.2中自动
ProducerRecord记录=新的ProducerRecord(“so55622224”,null,null,“foo”,标题);
RequestReplyFuture=template.sendReceive(记录);
ConsumerRecord reply=future.get();
System.out.println(“回复:+Reply.value()+”myHeader=”
+新字符串(reply.headers().lastHeader(“myHeader”).value());
};
}

我当前的
春季卡夫卡
版本是2.1.12。。。对于旧版本有什么解决方案吗?这是可能的,但您必须编写更多的代码。请参阅对我答案的编辑。我选择使用KafkaTemplate发送答案。
@SendTo
注释实际上除了调用KafkaTemplate之外没有什么作用,因为我必须自己构建消息。
@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()));
    };
}