注:项目实际依赖版本(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 = null
- value = 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





