What is KafkaTemplate in Spring for Apache Kafka, and how do send() and sendDefault() differ?
answer
- wrapper over KafkaProducer
- send(topic,...) vs sendDefault uses defaultTopic
- returns CompletableFuture<SendResult>
- async + thread-safe single bean
- built from ProducerFactory
basics
~10 sKafkaTemplate is Spring's helper for producing records to Kafka. send(topic, key, value) targets a named topic; sendDefault(key, value) uses a default topic preconfigured on the template, so you don't repeat the topic name.
solid answer
~40 sKafkaTemplate is a thin Spring wrapper over the native KafkaProducer that simplifies producing records and integrates with Spring (auto-config, message converters, observability). send(...) has overloads taking topic, optional partition, key, value, or a full ProducerRecord/Message<?>; sendDefault(...) drops the topic argument and uses the defaultTopic property set on the template. Sends are asynchronous: send() returns a CompletableFuture<SendResult> (ListenableFuture before 3.0). You add callbacks via whenComplete or block with get() if you need synchronous confirmation. The template is backed by a ProducerFactory that builds and pools the underlying producer. Because the Kafka producer is thread-safe, a single KafkaTemplate bean is shared across threads. You can also enable transactions on the factory to get send-within-transaction semantics via executeInTransaction.
code
java · 15 lineskafkaTemplate.setDefaultTopic("orders");
// explicit topic
kafkaTemplate.send("orders", order.id(), order)
.whenComplete((result, ex) -> {
if (ex == null) {
var md = result.getRecordMetadata();
log.info("sent to {}-{}@{}", md.topic(), md.partition(), md.offset());
} else {
log.error("send failed", ex);
}
});
// default topic
kafkaTemplate.sendDefault(order.id(), order);go deeper
Know KafkaTemplate produces records; send names a topic, sendDefault uses a preset default topic.
Explain the CompletableFuture<SendResult>, async batching, and thread-safe shared bean.
Discuss ProducerFactory backing, message converters, transactions, and acks interplay with the future.
Reason about throughput tradeoffs of blocking on get(), idempotence/ordering, and template configuration patterns at scale.
**Background.** Apache Kafka is a distributed log: producers append *records* (key + value + headers) to *topics*, which are split into *partitions*. The raw Java client exposes `KafkaProducer`, which you must configure, call `send()` on, and close. Spring for Apache Kafka (the `spring-kafka` project) adds a higher-level abstraction so you write less boilerplate and integrate with Spring features. **KafkaTemplate.** This is the central producing component. It is constructed from a `ProducerFactory<K,V>` (which holds the producer config map: `bootstrap.servers`, key/value serializers, etc.). The template borrows a producer from the factory, serializes your key/value, builds a `ProducerRecord`, and hands it to the underlying client. Because `KafkaProducer` is thread-safe, one `KafkaTemplate` bean is safely shared by all threads — you do **not** create one per request. **send() vs sendDefault().** - `send(String topic, K key, V value)` (and overloads with partition, timestamp, a `ProducerRecord`, or a Spring `Message<?>`) explicitly names the destination topic each call. - `sendDefault(K key, V value)` omits the topic and uses the `defaultTopic` you set on the template (e.g. `template.setDefaultTopic("orders")` or via the constructor). It is pure convenience for templates dedicated to a single topic; if no default topic is set, calling it throws. **Asynchrony and results.** `send()` returns a `CompletableFuture<SendResult<K,V>>` (since spring-kafka 3.0; earlier versions returned `ListenableFuture`). The `SendResult` carries the `ProducerRecord` and the broker `RecordMetadata` (partition, offset, timestamp). Producing is buffered and batched by the client, so the future completes only after the broker acknowledges per the `acks` setting. To react, use `future.whenComplete((result, ex) -> ...)`; to force synchronous behavior, call `future.get()` (blocks and surfaces failures), though that sacrifices throughput. **Edge cases.** Serializer exceptions and buffer-full conditions surface through the future or as exceptions on the calling thread. For ordering guarantees with retries, you rely on idempotence (`enable.idempotence=true`) rather than the template itself. Transactions are enabled by giving the `ProducerFactory` a `transactionIdPrefix`, after which `KafkaTemplate` exposes `executeInTransaction` and participates in Spring-managed transactions.
- Is send() synchronous or asynchronous, and how do you wait for the broker ack?Asynchronous. It returns a CompletableFuture<SendResult>; attach whenComplete for a callback, or call get() to block until the broker acknowledges (the future completes per the acks setting).
- Why is it fine to share one KafkaTemplate across many threads?Because the underlying KafkaProducer is thread-safe and designed to be shared; spring-kafka pools/reuses it via the ProducerFactory, so a single template bean serves all callers.
saying these in an interview costs you the question
- Claiming send() blocks until the record is persisted (it returns a future)
- Saying you should create a new KafkaTemplate per message/thread
- Confusing sendDefault with sending to a partition's default broker — it just uses a preset topic