注:项目实际依赖版本(Spring Boot 2.7.18 → spring-kafka 2.8.11 → kafka-clients 3.1.x),从 kafkaTemplate.send("test_topic", content) 出发,梳理框架源码里的完整调用链。
一、从项目代码进入框架
调用:
kafkaTemplate.send("test_topic", content);
对应 KafkaTemplate<String, String> 的重载:
// spring-kafka 2.8.11 - KafkaTemplate.java
public ListenableFuture<SendResult<K, V>> send(String topic, @Nullable V data) {
ProducerRecord<K, V> producerRecord = new ProducerRecord<>(topic, data);
return doSend(producerRecord);
}
此时构造的 ProducerRecord 为:
topic = "test_topic"key = nullvalue = content(你的 HTTP 参数text)partition = null(由分区器决定)timestamp = null(由 Producer 填当前时间)
二、完整调用链总览
三、分层详解
第 1 层:Bean 从何而来(启动时)
KafkaAutoConfiguration(Spring Boot 自动配置)在启动时创建:
// KafkaAutoConfiguration.java
@Bean
public DefaultKafkaProducerFactory kafkaProducerFactory(...) {
return new DefaultKafkaProducerFactory<>(this.properties.buildProducerProperties());
// 读取 application.yml 中的 bootstrap-servers、acks、serializer 等
}
@Bean
public KafkaTemplate kafkaTemplate(ProducerFactory kafkaProducerFactory, ...) {
return new KafkaTemplate<>(kafkaProducerFactory);
}
你的 application.yml 在这里被 KafkaProperties.buildProducerProperties() 转成 Map<String, Object>,最终传给 new KafkaProducer<>(configs, ...)。
第 2 层:KafkaTemplate.doSend() --- Spring Kafka 核心
protected ListenableFuture<SendResult<K, V>> doSend(final ProducerRecord<K, V> producerRecord) {
// ① 获取 Producer 实例
final Producer<K, V> producer = getTheProducer(producerRecord.topic());
// ② 创建 Spring 侧的 Future(对 jdk Future 的包装)
final SettableListenableFuture<SendResult<K, V>> future = new SettableListenableFuture<>();
// ③ 调用原生 KafkaProducer,并注册回调
Future<RecordMetadata> sendFuture =
producer.send(producerRecord, buildCallback(producerRecord, producer, future, sample));
// ④ 若同步失败(如序列化异常),立刻抛 KafkaException
if (sendFuture.isDone()) {
sendFuture.get(); // 可能抛异常
}
// ⑤ 若 autoFlush=true,立即 flush(默认 false)
if (this.autoFlush) {
flush();
}
return future; // 异步返回,不阻塞等待 Broker ack
}
要点:
doSend本身是非阻塞的:立刻返回ListenableFuture- 真正的 Broker 确认在
buildCallback里异步完成 - 你项目里没
.get(),所以 Controller 不会等 ack send()直接委托给delegate.send()close()采用「借用/归还」语义:单次send结束后的close()通常不会真正销毁底层 Producer,而是留给下次复用- spring-kafka 2.8.11 KafkaTemplate
- kafka-clients 3.1.2 KafkaProducer
- kafka-clients 3.1.2 Sender

