Java 编写customConsumerFactory和customKafkaListenerContainerFactory时未自动加载spring kafka属性

Java 编写customConsumerFactory和customKafkaListenerContainerFactory时未自动加载spring kafka属性,java,spring-boot,apache-kafka,spring-kafka-test,Java,Spring Boot,Apache Kafka,Spring Kafka Test,我想从application.properties加载我的spring kafka属性,必须使用spring自动配置加载这些属性。我的问题是由以下原因引起的:java.lang.IllegalStateException:没有可用的确认作为参数,侦听器容器必须具有手动确认模式才能填充确认,但是我已经在属性文件spring.kafka.listener.ack mode=MANUAL immediate中对此属性进行了设置,但是因为它是我的自定义fooKafkaListenerContainerF

我想从application.properties加载我的spring kafka属性,必须使用spring自动配置加载这些属性。我的问题是由以下原因引起的:java.lang.IllegalStateException:没有可用的确认作为参数,侦听器容器必须具有手动确认模式才能填充确认,但是我已经在属性文件spring.kafka.listener.ack mode=MANUAL immediate中对此属性进行了设置,但是因为它是我的自定义fooKafkaListenerContainerFactory,所以无法选择此设置。我想要的是不需要手动设置,它应该从我的application.properies中获取@加里·拉塞尔:非常感谢你的帮助

我的代码如下所示

package com.foo;

import org.apache.kafka.common.serialization.StringDeserializer;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.kafka.ConcurrentKafkaListenerContainerFactoryConfigurer;
import org.springframework.boot.autoconfigure.kafka.KafkaProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.kafka.config.ConcurrentKafkaListenerContainerFactory;
import org.springframework.kafka.core.ConsumerFactory;
import org.springframework.kafka.core.DefaultKafkaConsumerFactory;
import org.springframework.kafka.support.serializer.JsonDeserializer;

import com.foo.FooKafkaDTO;

@Configuration
public class KafkaConsumerConfig {

    @Autowired
    private KafkaProperties kafkaProperties;

    @Bean
    @ConditionalOnMissingBean(ConsumerFactory.class)
    public ConsumerFactory<?, ?> kafkaConsumerFactory() {

        return new DefaultKafkaConsumerFactory<>(kafkaProperties.buildConsumerProperties());
    }

    @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;
    }

    @Bean
    public ConsumerFactory<String, FooKafkaDTO> fooConsumerFactory() {

        return new DefaultKafkaConsumerFactory<>(
                kafkaProperties.buildConsumerProperties(), new StringDeserializer(), new JsonDeserializer<>(FooKafkaDTO.class));
    }

    @Bean
    public ConcurrentKafkaListenerContainerFactory<String, FooKafkaDTO> fooKafkaListenerContainerFactory(
            ConcurrentKafkaListenerContainerFactoryConfigurer configurer,
            ConsumerFactory<String, FooKafkaDTO> fooConsumerFactory) {

        ConcurrentKafkaListenerContainerFactory<String, FooKafkaDTO> factory =
                new ConcurrentKafkaListenerContainerFactory<>();
        factory.setConsumerFactory(fooConsumerFactory());
        return factory;
    }
}


Here are my properties 

spring.kafka.bootstrap-servers=localhost:9092
spring.kafka.listener.ack-mode=manual-immediate
spring.kafka.consumer.group-id=group_id
spring.kafka.consumer.auto-offset-reset=latest
spring.kafka.consumer.enable.auto.commit=false
spring.kafka.consumer.key-deserialize=org.springframework.kafka.support.serializer.JsonDeserializer
spring.kafka.consumer.value-deserialize=org.springframework.kafka.support.serializer.JsonDeserializer


Here is my listener

@Service
public class Consumer {

    private static final Log LOG = LogFactory.getLog(Consumer.class);

    @KafkaListener(
            topicPartitions = {@TopicPartition(topic = "outbox.foo",
                    partitionOffsets = @PartitionOffset(partition = "0", initialOffset = "0"))},
            groupId = "group_id",
            containerFactory = "fooKafkaListenerContainerFactory")
    public void consume(@Payload FooKafkaDTO fooKafkaDTO, Acknowledgment acknowledgment,
            @Headers MessageHeaders headers) {

        LOG.info("offset:::" + Long.valueOf(headers.get(KafkaHeaders.OFFSET).toString()));
        LOG.info(String.format("$$ -> Consumed Message -> %s", fooKafkaDTO));
        acknowledgment.acknowledge();

    }
}
package com.foo;
导入org.apache.kafka.common.serialization.StringDeserializer;
导入org.springframework.beans.factory.annotation.Autowired;
导入org.springframework.beans.factory.annotation.Value;
导入org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
导入org.springframework.boot.autoconfigure.kafka.ConcurrentKafkaListenerContainerFactoryConfigurer;
导入org.springframework.boot.autoconfigure.kafka.KafkaProperties;
导入org.springframework.context.annotation.Bean;
导入org.springframework.context.annotation.Configuration;
导入org.springframework.kafka.config.ConcurrentKafkaListenerContainerFactory;
导入org.springframework.kafka.core.ConsumerFactory;
导入org.springframework.kafka.core.DefaultKafkaConsumerFactory;
导入org.springframework.kafka.support.serializer.JsonDeserializer;
导入com.foo.FooKafkaDTO;
@配置
公共类卡夫卡消费者配置{
@自动连线
私人卡夫卡财产卡夫卡财产;
@豆子
@ConditionalOnMissingBean(ConsumerFactory.class)
公共消费工厂卡夫卡消费工厂(){
返回新的DefaultKafkaConsumerFactory(kafkaProperties.buildConsumerProperties());
}
@豆子
@ConditionalOnMissingBean(name=“kafkaListenerContainerFactory”)
公共并发kafkaListenerContainerFactory kafkaListenerContainerFactory(
ConcurrentKafkaListenerContainerFactoryConfigurer配置器,
卡夫卡消费工厂(卡夫卡消费工厂){
ConcurrentKafkListenerContainerFactory=新ConcurrentKafkListenerContainerFactory();
configurer.configure(工厂、卡夫卡消费工厂);
返回工厂;
}
@豆子
公共消费者工厂食品消费者工厂(){
返回新的DefaultKafka消费者工厂(
kafkaProperties.buildConsumerProperties()、新的StringDeserializer()、新的JsonDeserializer(FooKafkaDTO.class));
}
@豆子
公共并发KafkalistenerContainerFactory食品KafkalistenerContainerFactory(
ConcurrentKafkaListenerContainerFactoryConfigurer配置器,
消费者工厂食品(消费者工厂){
ConcurrentKafkalistener集装箱工厂=
新的ConcurrentKafkaListenerContainerFactory();
setConsumerFactory(fooConsumerFactory());
返回工厂;
}
}
这是我的财产
bootstrap servers=localhost:9092
spring.kafka.listener.ack模式=手动立即
spring.kafka.consumer.group id=group\u id
spring.kafka.consumer.auto offset reset=最新
spring.kafka.consumer.enable.auto.commit=false
spring.kafka.consumer.key反序列化=org.springframework.kafka.support.serializer.JsonDeserializer
spring.kafka.consumer.value反序列化=org.springframework.kafka.support.serializer.JsonDeserializer
这是我的听众
@服务
公共类消费者{
私有静态最终日志=LogFactory.getLog(Consumer.class);
@卡夫卡(
topicPartitions={@TopicPartition(topic=“outbox.foo”,
PartitionOffset=@PartitionOffset(partition=“0”,initialOffset=“0”))},
groupId=“group\u id”,
containerFactory=“fooKafkaListenerContainerFactory”)
公共无效消费(@Payload FooKafkaDTO FooKafkaDTO,确认,
@页眉消息页眉(页眉){
LOG.info(“offset:::”+Long.valueOf(headers.get(KafkaHeaders.offset.toString());
LOG.info(String.format(“$$->已消费消息->%s”,fooKafkaDTO));
确认。确认();
}
}

在阅读了spring kafka的文档之后!我可以找到这个代码,它取代了整个样板代码。我已经简化了我的KafkanConsumerConfig类,现在看起来如下所示

package com.foo

import java.util.Map;

import org.springframework.boot.autoconfigure.kafka.KafkaProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.kafka.core.DefaultKafkaConsumerFactory;
import org.springframework.kafka.support.serializer.JsonDeserializer;

import com.foo.FooKafkaDTO;

@Configuration
public class KafkaConsumerConfig {

    @Bean
    public DefaultKafkaConsumerFactory fooDTOConsumerFactory(KafkaProperties properties) {

        Map<String, Object> props = properties.buildConsumerProperties();
        return new DefaultKafkaConsumerFactory(props,
                new JsonDeserializer<>(String.class)
                        .forKeys()
                        .ignoreTypeHeaders(),
                new JsonDeserializer<>(FooKafkaDTO.class)
                        .ignoreTypeHeaders());

    }
}
package com.foo
导入java.util.Map;
导入org.springframework.boot.autoconfigure.kafka.KafkaProperties;
导入org.springframework.context.annotation.Bean;
导入org.springframework.context.annotation.Configuration;
导入org.springframework.kafka.core.DefaultKafkaConsumerFactory;
导入org.springframework.kafka.support.serializer.JsonDeserializer;
导入com.foo.FooKafkaDTO;
@配置
公共类卡夫卡消费者配置{
@豆子
公共默认卡夫卡消费工厂食品消费工厂(卡夫卡属性){
Map props=properties.buildConsumerProperties();
返回新的默认卡夫卡消费工厂(道具,
新的JsonDeserializer(String.class)
.forKeys()
.ignoreTypeHeaders(),
新的JsonDeserializer(FooKafkaDTO.class)
.ignoreTypeHeaders());
}
}

@Gary Russell非常感谢您的意见。如果您向某个特定的人提问,最好使用电子邮件