卡夫卡的消费动态拿起主题

时间:2019-01-31 18:01:06

标签: spring-boot configuration kafka-consumer-api spring-kafka

我在弹簧引导配置卡夫卡消费者。这里的配置类:

@EnableKafka
@Configuration
@PropertySource({"classpath:kafka.properties"})
public class KafkaConsumerConfig {

    @Autowired
    private Environment env;

    @Bean
    public ConsumerFactory<String, GenericData.Record> consumerFactory() {

        dataRiverProps.put(ConsumerConfig.BOOTSTRAP_SERVERS_CONFIG, env.getProperty("bootstrap.servers"));
        dataRiverProps.put(ConsumerConfig.GROUP_ID_CONFIG, env.getProperty("group.id"));
        dataRiverProps.put(ConsumerConfig.ENABLE_AUTO_COMMIT_CONFIG, env.getProperty("enable.auto.commit"));
        dataRiverProps.put(ConsumerConfig.AUTO_COMMIT_INTERVAL_MS_CONFIG, env.getProperty("auto.commit.interval.ms"));
        dataRiverProps.put(ConsumerConfig.SESSION_TIMEOUT_MS_CONFIG, env.getProperty("session.timeout.ms"));
        dataRiverProps.put(ConsumerConfig.AUTO_OFFSET_RESET_CONFIG, env.getProperty("auto.offset.reset"));

        dataRiverProps.put(KafkaAvroDeserializerConfig.SCHEMA_REGISTRY_URL_CONFIG, env.getProperty("schema.registry.url"));
        dataRiverProps.put(ConsumerConfig.KEY_DESERIALIZER_CLASS_CONFIG, KafkaAvroDeserializer.class.getName());
        dataRiverProps.put(ConsumerConfig.VALUE_DESERIALIZER_CLASS_CONFIG, KafkaAvroDeserializer.class.getName());

        return new DefaultKafkaConsumerFactory<>(dataRiverProps);
    }

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

和这里的消费者:

@Component
public class KafkaConsumer {

    @Autowired
    private MessageProcessor messageProcessor;

    @KafkaListener(topics = "#{'${kafka.topics}'.split(',')}", containerFactory = "kafkaListenerContainerFactory")
    public void consumeAvro(GenericData.Record message) {
        messageProcessor.process();
    }

}

请注意,我正在使用 topics =“#{'$ {kafka.topics}'。split(',')}” 从属性文件中选择主题。 这就是我的kafka.properties文件的样子:

kafka.topics=pwdChange,pwdCreation
bootstrap.servers=aaa.bbb.com:37900
group.id=pwdManagement
enable.auto.commit=true
auto.commit.interval.ms=1000
session.timeout.ms=30000
schema.registry.url=http://aaa.bbb.com:37800

现在,如果我要向订阅添加一个新主题,请说pwdExpire,然后按如下所示修改prop文件:

kafka.topics=pwdChange,pwdCreation,pwdExpire

有没有办法为我的消费者开始订阅这个新主题无需重新启动服务器? 我已经找到了这篇帖子Spring Kafka - Subscribe new topics during runtime,但是文档中有关于 metadata.max.age.ms 的说法:

  

以毫秒为单位的时间段,之后我们强制刷新   即使我们没有看到任何分区领导更改为元数据   主动发现任何新的代理或分区。

对我来说听起来是行不通的。感谢您的帮助!

1 个答案:

答案 0 :(得分:1)

否;唯一的方法是使用主题模式;当添加新主题(与模式匹配)时,默认情况下,代理会在5分钟后将其添加到订阅中。

但是,您可以在运行时为新主题添加新的侦听器容器。

另一种选择是将@KafkaListener bean加载到子应用程序上下文中,并在每次主题更改时重新创建上下文。

编辑

请参阅的Javadoc KafkaConsumer.subscribe(Pattern pattern) ...

/**
 * Subscribe to all topics matching specified pattern to get dynamically assigned partitions.
 * The pattern matching will be done periodically against topics existing at the time of check.
 * <p>
 ...