当使用自定义valueDeserializer时,如何在.properties / .yaml中设置ack-mode?

时间:2017-08-30 10:23:49

标签: java spring spring-boot spring-kafka

有一个Spring-boot程序正在使用kafka中的JSON数据。 Afaik设置JsonDeserializer的唯一方法是使用java配置,即它不能在.yaml(或.properties)文件中设置,例如

@Configuration
public class KafkaConfig {

    @Bean
    public ConsumerFactory<String, DeserObject> consumerFactory( final KafkaProperties properties ) {
        JsonDeserializer<DeserObject> jsonDeserializer = new JsonDeserializer<>( DeserObject.class );
        return new DefaultKafkaConsumerFactory<>(
                properties.buildConsumerProperties(),  // so consumer could still be configured in .yaml
                new StringDeserializer(),              // key deserializer
                jsonDeserializer                       // value deserializer
        );
    }

    @Bean
    public KafkaListenerContainerFactory kafkaListenerContainerFactory( final ConsumerFactory<String, DeserObject> consumerFactory ) {
        ConcurrentKafkaListenerContainerFactory<String, DeserObject> factory = new ConcurrentKafkaListenerContainerFactory<>();
        factory.setConsumerFactory( consumerFactory );
        return factory;
    }
}

既然我们自己正在创建ListenerContainerFactory,则无法通过.yaml设置AckMode

spring:
  kafka:
    listener:
      ack-mode: manual

因为它不会被拾取(因为ListernerContainerFactory不是由boot自动配置的,因为我们正在创建它。)

所以问题是:是否有任何方式从yaml配置ackMode,或者我们必须从java中做到这一点?:

@Bean
public KafkaListenerContainerFactory kafkaListenerContainerFactory( final ConsumerFactory<String, DeserObject> consumerFactory ) {
    ConcurrentKafkaListenerContainerFactory<String, DeserObject> factory = new ConcurrentKafkaListenerContainerFactory<>();
    factory.setConsumerFactory( consumerFactory );
    factory.getContainerProperties().setAckMode( MANUAL );  // !! AckMode needs to be set in Java
    return factory;
}

我猜或者这也可以通过KafkaProperties注入,但这感觉很糟糕:

@Bean
public KafkaListenerContainerFactory kafkaListenerContainerFactory( final KafkaProperties properties, final ConsumerFactory<String, DeserObject> consumerFactory ) {
    ConcurrentKafkaListenerContainerFactory<String, DeserObject> factory = new ConcurrentKafkaListenerContainerFactory<>();
    factory.setConsumerFactory( consumerFactory );
    factory.getContainerProperties().setAckMode( properties.getListener().getAckMode() );
    return factory;
}

1 个答案:

答案 0 :(得分:1)

您需要使用Boot的ConcurrentKafkaListenerContainerFactoryConfigurer来填充引导属性。这是您未提供的标准bean定义...

@Bean
@ConditionalOnMissingBean(name = "kafkaListenerContainerFactory")
public ConcurrentKafkaListenerContainerFactory<?, ?> kafkaListenerContainerFactory(
        ConcurrentKafkaListenerContainerFactoryConfigurer configurer,
        ConsumerFactory<Object, Object> kafkaConsumerFactory) {
    ConcurrentKafkaListenerContainerFactory<Object, Object> factory = new ConcurrentKafkaListenerContainerFactory<Object, Object>();
    configurer.configure(factory, kafkaConsumerFactory);
    return factory;
}