如何在Kafka批处理侦听器中访问MessageHeaders

时间:2019-01-08 06:09:20

标签: spring-boot spring-kafka

我具有以下针对Kafka的自动配置类:

@Configuration
@EnableKafka
@ConditionalOnClass(KafkaReceiver.class)
@ConditionalOnProperty({"spring.kafka.bootstrap-servers"})
public class KafkaAutoConfiguration<T> { @Value("${spring.kafka.bootstrap-servers}")

    private String bootstrapServers;

    private KafkaProperties kafkaConfig;
    private String groupId;

    @Autowired
    public void setKafkaProperties(KafkaProperties properties) {
        this.kafkaConfig = properties;
    }

    @Bean
    public Map<String, Object> consumerConfigs() {
        Map<String, Object> props = new HashMap<>();

        props.put(ConsumerConfig.BOOTSTRAP_SERVERS_CONFIG,
            bootstrapServers);
        props.put(ConsumerConfig.KEY_DESERIALIZER_CLASS_CONFIG,
            StringDeserializer.class);
        props.put(ConsumerConfig.VALUE_DESERIALIZER_CLASS_CONFIG,
                    StringDeserializer.class);
        props.put(ConsumerConfig.VALUE_DESERIALIZER_CLASS_CONFIG,
            org.apache.kafka.common.serialization.ByteArrayDeserializer.class);
        props.put(ConsumerConfig.GROUP_ID_CONFIG, kafkaConfig.getGroupId());
        props.put(ConsumerConfig.AUTO_OFFSET_RESET_CONFIG, "earliest");

        return props;
    }

    @Bean
    public ConsumerFactory<String, String> consumerFactory() {
        return new DefaultKafkaConsumerFactory<>(consumerConfigs());
    }

    @Bean
    public ConcurrentKafkaListenerContainerFactory<String, String> kafkaListenerContainerFactory() {
        ConcurrentKafkaListenerContainerFactory<String, String> factory =
            new ConcurrentKafkaListenerContainerFactory<>();
        factory.setConsumerFactory(consumerFactory());

        return factory;
    }

    @Bean
    public ConcurrentKafkaListenerContainerFactory<String, String> kafkaBatchListenerContainerFactory() {
        ConcurrentKafkaListenerContainerFactory<String, String> factory =
            new ConcurrentKafkaListenerContainerFactory<>();
        factory.setConsumerFactory(consumerFactory());
        factory.setBatchListener(true);

        return factory;
    }

    @Bean
    public DefaultKafkaHeaderMapper headerMapper(){
        return new DefaultKafkaHeaderMapper();
    }

    @Bean("simpleReceiver")
    @ConditionalOnMissingBean(name = "simpleReceiver")
    @ConditionalOnProperty({"service.kafka.consumer.topics"})
    public KafkaReceiver simpleReceiver() {
        return new KafkaSimpleReceiver();
    }

    @Bean("batchReceiver")
    @ConditionalOnMissingBean(name = "batchReceiver")
    @ConditionalOnProperty({"service.kafka.consumer.batch-topics"})
    public KafkaReceiver batchReceiver() {
        return new KafkaBatchReceiver();
    }
}

简单的侦听器bean:

public class KafkaSimpleReceiver implements KafkaReceiver {
    @KafkaListener(topics = "#{'${service.kafka.consumer.topics}'.split(',')}", containerFactory = "kafkaListenerContainerFactory")
    public void receive(ConsumerRecord record, @Headers MessageHeaders headers) throws KafkaException {
    }
}

批处理侦听器bean:

public class KafkaBatchReceiver implements KafkaReceiver {

    @KafkaListener(topics = "#{'${service.kafka.consumer.batch-topics}'.split(',')}", containerFactory = "kafkaBatchListenerContainerFactory")
    public void receive(List<ConsumerRecord> records, @Headers MessageHeaders headers) throws KafkaException {

    }
}

简单侦听器工作正常,但批处理侦听器出现以下错误。在这种情况下,我们如何访问MessageHeaders?

A parameter of type 'List<ConsumerRecord>' must be the only parameter (except for an optional 'Acknowledgment' and/or 'Consumer')  

编辑

这就是我将ConsumerRecord转换为MessageHeaders的方法

public void receive(List<ConsumerRecord> records) { 
    for(ConsumerRecord record : records) { 
        Map<String, Object> headersList = new HashMap<>(); 
        for(final Header h : record.headers()) { 
            headersList.put(h.key(), new String(h.value())); 
        } 
    MessageHeaders headers = new MessageHeaders(headersList); 
    } 
}

1 个答案:

答案 0 :(得分:0)

您可以获得Message<?>的列表。

@KafkaListener(topics = "so54086076", id = "so54086076")
public void listen(List<Message<?>> records) {
    System.out.println(records.size() + ":" + records);
}

消息有效载荷将为ConsumerRecord.value();其他ConsumerRecord属性将位于标题中。