升级Spring Boot与Spring Cloud后Kafka配置启动空指针异常如何修复
问题根因
错误栈中的NPE由两个原因共同导致:
- 高版本
spring-kafka的DefaultKafkaProducerFactory内部改用ConcurrentHashMap存储配置,而ConcurrentHashMap不允许value为null,当你传入的配置属性为空时就会触发空指针。 - 你将
@RefreshScope直接标注在@Configuration配置类上,Spring Boot 2.6.x之后对该组合注解的处理逻辑发生变化,配置属性的注入时机晚于Bean的创建时机,导致keySerializer、valueSerializer、bootstrapServers三个属性还未被赋值就被调用,最终生成的配置map里存在null值。 - 仅给
KafkaTemplate加@RefreshScope也无法实现配置热刷新的效果,依赖的ProducerFactory和配置Bean没有同步刷新。
修复方案
推荐将配置属性单独抽离为独立的属性类,符合Spring Boot最佳实践,同时调整@RefreshScope的作用位置:
步骤1:定义独立的配置属性类
import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.cloud.context.config.annotation.RefreshScope; @RefreshScope @ConfigurationProperties(prefix = "kafka.status.producer") public class StatusKafkaProducerProperties { private String keySerializer; private String valueSerializer; private String bootstrapServers; public String getKeySerializer() { return keySerializer; } public void setKeySerializer(String keySerializer) { this.keySerializer = keySerializer; } public String getValueSerializer() { return valueSerializer; } public void setValueSerializer(String valueSerializer) { this.valueSerializer = valueSerializer; } public String getBootstrapServers() { return bootstrapServers; } public void setBootstrapServers(String bootstrapServers) { this.bootstrapServers = bootstrapServers; } }
在启动类上添加@ConfigurationPropertiesScan注解,确保属性类能被Spring扫描到。
步骤2:调整Kafka配置类
import org.apache.kafka.clients.producer.ProducerConfig; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.kafka.core.DefaultKafkaProducerFactory; import org.springframework.kafka.core.KafkaTemplate; import org.springframework.kafka.core.ProducerFactory; import org.springframework.cloud.context.config.annotation.RefreshScope; import java.util.HashMap; import java.util.Map; @Configuration public class StatusKafkaProducerConfig { @Bean @RefreshScope public Map<String, Object> producerConfigs(StatusKafkaProducerProperties properties) { Map<String, Object> propertiesMap = new HashMap<>(); propertiesMap.put(ProducerConfig.KEY_SERIALIZER_CLASS_CONFIG, properties.getKeySerializer()); propertiesMap.put(ProducerConfig.VALUE_SERIALIZER_CLASS_CONFIG, properties.getValueSerializer()); propertiesMap.put(ProducerConfig.BOOTSTRAP_SERVERS_CONFIG, properties.getBootstrapServers()); return propertiesMap; } @Bean @RefreshScope public ProducerFactory<String, String> producerFactory(Map<String, Object> producerConfigs) { return new DefaultKafkaProducerFactory<>(producerConfigs); } @Bean @RefreshScope public KafkaTemplate<String, String> kafkaTemplate(ProducerFactory<String, String> producerFactory) { return new KafkaTemplate<>(producerFactory); } }
步骤3:检查配置文件
确保你的application.yml或application.properties中存在对应配置,示例如下:
kafka: status: producer: bootstrap-servers: 127.0.0.1:9092 key-serializer: org.apache.kafka.common.serialization.StringSerializer value-serializer: org.apache.kafka.common.serialization.StringSerializer
如果你不想单独抽离属性类,也可以直接移除原配置类上的@RefreshScope注解,给producerConfigs、producerFactory、kafkaTemplate三个Bean都加上@RefreshScope即可临时解决问题。
内容的提问来源于stack exchange,提问作者Peter Penzov
相关产品推荐
相关产品推荐

