我计划使用Spring Kafka客户端在Spring Boot应用程序中使用和生成来自kafka设置的消息。我在Kafka 0.11中看到了对详细here的自定义标头的支持。虽然它可供本地Kafka制作人和消费者使用,但我没有看到在Spring Kafka中添加/阅读自定义标题的支持。
我正在尝试基于我希望存储在邮件头中的重试计数来实现消息的DLQ,而不必解析有效负载。
答案 0 :(得分:3)
好吧,Spring Kafka提供了自 2.0版以来的标头支持:https://docs.spring.io/spring-kafka/docs/2.1.2.RELEASE/reference/html/_reference.html#headers
您可以拥有该KafkaHeaderMapper
个实例,并在通过Message
发送之前将其用于填充KafkaTemplate.send(Message<?> message)
标题。或者您可以使用普通KafkaTemplate.send(ProducerRecord<K, V> record)
。
当您使用KafkaMessageListenerContainer
接收记录时,可以通过注入KafkaHeaderMapper
的{{1}}向MessagingMessageConverter
提供RecordMessagingMessageListenerAdapter
。
因此,任何自定义标头都可以转移。
答案 1 :(得分:1)
当我偶然发现这个问题时,我正在寻找答案。但是,我使用的是ProducerRecord<?, ?>
类而不是Message<?>
,因此标头映射器似乎并不相关。
这是我添加自定义标头的方法:
var record = new ProducerRecord<String, String>(topicName, "Hello World");
record.headers().add("foo", "bar".getBytes());
kafkaTemplate.send(record);
现在(在使用之前)读取标头,我添加了一个自定义拦截器。
import java.util.List;
import lombok.extern.slf4j.Slf4j;
import org.apache.kafka.clients.consumer.ConsumerInterceptor;
import org.apache.kafka.clients.consumer.ConsumerRecord;
import org.apache.kafka.clients.consumer.ConsumerRecords;
@Slf4j
public class MyConsumerInterceptor implements ConsumerInterceptor<Object, Object> {
@Override
public ConsumerRecords<Object, Object> onConsume(ConsumerRecords<Object, Object> records) {
Set<TopicPartition> partitions = records.partitions();
partitions.forEach(partition -> interceptRecordsFromPartition(records.records(partition)));
return records;
}
private void interceptRecordsFromPartition(List<ConsumerRecord<Object, Object>> records) {
records.forEach(record -> {
var myHeaders = new ArrayList<Header>();
record.headers().headers("MyHeader").forEach(myHeaders::add);
log.info("My Headers: {}", myHeaders);
// Do with header as you see fit
});
}
@Override public void onCommit(Map<TopicPartition, OffsetAndMetadata> offsets) {}
@Override public void close() {}
@Override public void configure(Map<String, ?> configs) {}
}
最后一点是使用以下(Spring Boot)配置将此拦截器注册到Kafka Consumer Container:
import java.util.Map;
import org.apache.kafka.clients.consumer.ConsumerConfig;
import org.springframework.boot.autoconfigure.kafka.KafkaProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.kafka.core.ConsumerFactory;
import org.springframework.kafka.core.DefaultKafkaConsumerFactory;
@Configuration
public class MessagingConfiguration {
@Bean
public ConsumerFactory<?, ?> kafkaConsumerFactory(KafkaProperties properties) {
Map<String, Object> consumerProperties = properties.buildConsumerProperties();
consumerProperties.put(ConsumerConfig.INTERCEPTOR_CLASSES_CONFIG, MyConsumerInterceptor.class.getName());
return new DefaultKafkaConsumerFactory<>(consumerProperties);
}
}