设置kafka主题过滤器

时间:2018-06-12 00:45:49

标签: java spring apache-kafka

我正在使用此tutorial来设置项目。一切正常,直到我在接收器上添加客户容器工厂。这是我的KafkaReciverConfig

@EnableKafka
@Configuration
public class ReceiverConfig {
    @Value("${spring.kafka.bootstrap-servers}")
    private String bootstrapServers;

    @Bean
    public Map<String, Object> consumerConfigs() {
        Map<String, Object> props = new HashMap<>();
        props.put(BOOTSTRAP_SERVERS_CONFIG, bootstrapServers);
        props.put(GROUP_ID_CONFIG, "app.topic");
        props.put(AUTO_OFFSET_RESET_CONFIG, "earliest");
        props.put(KEY_DESERIALIZER_CLASS_CONFIG, StringDeserializer.class);
        props.put(VALUE_DESERIALIZER_CLASS_CONFIG, JsonDeserializer.class);
        return props;
    }

    @Bean
    public ConsumerFactory<String, TopicPayload> consumerFactory() {
        return new DefaultKafkaConsumerFactory<>(consumerConfigs(), new StringDeserializer(),
                new JsonDeserializer<>(TopicPayload.class));
    }

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

这是我的Receiver.liste方法

@KafkaListener(id = "app.topic", topics = "${app.topic.topicname}", containerFactory = "filterKafkaListenerContainerFactory")
public void listen(@Payload TopicPayload payload) {
    LOGGER.info("-------------------- " + payload);
}

如果我没有指定containerFactory,它可以正常工作。但是我指定的那一刻(我打算在这里添加一些过滤逻辑)我得到以下错误

***************************
APPLICATION FAILED TO START
***************************

Description:

Parameter 1 of method kafkaListenerContainerFactory in org.springframework.boot.autoconfigure.kafka.KafkaAnnotationDrivenConfiguration required a bean of type 'org.springframework.kafka.core.ConsumerFactory' that could not be found.
    - Bean method 'kafkaConsumerFactory' in 'KafkaAutoConfiguration' not loaded because @ConditionalOnMissingBean (types: org.springframework.kafka.core.ConsumerFactory; SearchStrategy: all) found beans of type 'org.springframework.kafka.core.ConsumerFactory' consumerFactory


Action:

1 个答案:

答案 0 :(得分:0)

此错误是由KafkaAnnotationDrivenConfiguration类引起的。

在KafkaAnnotationDrivenConfiguration类中,如果没有名为“kafkaListenerContainerFactory”的bean,请将kafkaListenerContainerFactory注册为bean。

以下是在KafkaAnnotationDrivenConfiguration中注册kafkaListenerContainerFactory bean的方法代码。

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

此方法将ConsumerFactory <Object, Object>作为参数。但是,您注册的ConsumerFactory是ConsumerFactory <String, TopicPayload>所以Spring没有找到ConsumerFactory <Object, Object>类型的bean并抛出异常

解决方案是不将ConsumerFactory和consumerConfigs注册为bean。在这种情况下,ConsumerFactory将被KafkaAutoConfiguration自动注册为bean。(仅当没有ConsumerFactory类型的bean时,KafkaAutoConfiguration才会自动注册bean。)

public Map<String, Object> consumerConfigs() {
    Map<String, Object> props = new HashMap<>();
    props.put(BOOTSTRAP_SERVERS_CONFIG, bootstrapServers);
    props.put(GROUP_ID_CONFIG, "app.topic");
    props.put(AUTO_OFFSET_RESET_CONFIG, "earliest");
    props.put(KEY_DESERIALIZER_CLASS_CONFIG, StringDeserializer.class);
    props.put(VALUE_DESERIALIZER_CLASS_CONFIG, JsonDeserializer.class);
    return props;
}

public ConsumerFactory<String, TopicPayload> consumerFactory() {
    return new DefaultKafkaConsumerFactory<>(consumerConfigs(), new StringDeserializer(),
            new JsonDeserializer<>(TopicPayload.class));
}

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

更简单的方法是使用名称kafkaListenerContainerFactory而不是名称filterKafkaListenerContainerFactory。

@Bean
public Map<String, Object> consumerConfigs() {
    Map<String, Object> props = new HashMap<>();
    props.put(BOOTSTRAP_SERVERS_CONFIG, bootstrapServers);
    props.put(GROUP_ID_CONFIG, "app.topic");
    props.put(AUTO_OFFSET_RESET_CONFIG, "earliest");
    props.put(KEY_DESERIALIZER_CLASS_CONFIG, StringDeserializer.class);
    props.put(VALUE_DESERIALIZER_CLASS_CONFIG, JsonDeserializer.class);
    return props;
}

@Bean
public ConsumerFactory<String, TopicPayload> consumerFactory() {
    return new DefaultKafkaConsumerFactory<>(consumerConfigs(), new StringDeserializer(),
            new JsonDeserializer<>(TopicPayload.class));
}

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

解释起来有点困难。如果您知道Spring引导的自动配置,那将很容易理解。

我希望我的样本有效。