Key Takeaways
- Spring Boot can configure Kafka infrastructure for you, but delivery guarantees still depend on producer settings, offset commits, and application behavior.
NewTopicbeans declare topics for startup administration; removing a bean does not automatically delete its topic.KafkaTemplate.send()returns a future. Successful completion does not mean a consumer finished processing the message.- Listener concurrency creates consumers, not additional partitions. Retries and dead-letter recovery require an explicit failure-handling policy.
Spring Boot integrates Kafka through topic declarations, a producer abstraction called KafkaTemplate, and listener methods annotated with @KafkaListener. These Spring Boot Kafka interview questions explain those APIs, then cover the delivery, concurrency, and failure scenarios that distinguish a working demo from a production design.
If partitions and consumer groups are unfamiliar, review Kafka architecture first.
Spring Boot Kafka Interview Questions: Setup and Topics
1. What does Spring Boot configure for Kafka?
With Kafka support on the classpath and no replacement beans supplied, Boot provides producer and consumer factories, a KafkaTemplate, a KafkaAdmin, and a default listener container factory. This is Boot auto-configuration, not behavior you get from every plain Spring application.
Example baseline: Spring Boot 4.1.1 manages Spring for Apache Kafka 4.1.1 and Kafka client 4.2.1. Use Boot’s dependency management rather than independently pinning those libraries. The examples use Java 21, which is within this Boot release’s supported Java range.
Create a Maven Boot project using that baseline and the package com.example.kafka. Keep its generated application entry point and Maven plugin. Its Kafka dependency should look like this pom.xml fragment:
<!-- Inside the dependencies section of the Boot-managed pom.xml -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-kafka</artifactId>
</dependency>For a disposable local broker, the official Kafka quickstart provides this Docker command. Run the Java application on your host for the following localhost configuration.
docker run -p 9092:9092 apache/kafka:4.2.22. How do NewTopic and KafkaAdmin create topics?
A NewTopic bean describes a topic; KafkaAdmin applies the declaration during application context initialization. Put this complete class in src/main/java/com/example/kafka/KafkaTopicConfiguration.java:
package com.example.kafka;
import org.apache.kafka.clients.admin.NewTopic;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.kafka.config.TopicBuilder;
@Configuration(proxyBeanMethods = false)
public class KafkaTopicConfiguration {
@Bean
public NewTopic myTopic() {
return TopicBuilder.name("myTopic")
.partitions(10)
.replicas(1)
.build();
}
}The original replicas(3) example requires at least three brokers. This example uses one replica for a single-broker development setup; it provides no replica redundancy.
For an existing topic, the admin can increase its partition count when the declaration requests more partitions. Existing topic configuration changes require the relevant admin configuration; declarations are not a general-purpose cluster reconciliation system. Topic deletion is an explicit administrative operation, not a consequence of removing a bean.
3. What happens when the broker is unavailable at startup?
spring.kafka.admin.fail-fast defaults to false. The admin can log a broker-availability failure while allowing the application context to continue; that does not prove the application is ready to send or consume messages. Setting it to true makes broker unavailability fatal during admin initialization.
Use the following src/main/resources/application.yml for the examples. The Boot property configures the admin’s Java-level fatalIfBrokerNotAvailable setting; that Java name is not the Boot configuration key.
spring:
kafka:
bootstrap-servers: localhost:9092
admin:
fail-fast: true
producer:
key-serializer: org.apache.kafka.common.serialization.StringSerializer
value-serializer: org.apache.kafka.common.serialization.StringSerializer
acks: all
properties:
"[enable.idempotence]": true
consumer:
key-deserializer: org.apache.kafka.common.serialization.StringDeserializer
value-deserializer: org.apache.kafka.common.serialization.StringDeserializer
enable-auto-commit: false
auto-offset-reset: earliest
listener:
ack-mode: recordProducer Interview Questions: KafkaTemplate and Delivery
4. How are serializers and deserializers selected?
Kafka serializers turn keys and values into bytes; deserializers turn those bytes back into application values. Configure key and value implementations separately. Declaring KafkaTemplate<String, String> does not itself configure the wire format.
The YAML explicitly selects string implementations. For JSON objects, Spring Kafka 4 provides JacksonJsonSerializer and JacksonJsonDeserializer; configure the target types and trusted packages deliberately. See the Spring Boot Kafka consumer JSON example for a focused walkthrough.
5. What does KafkaTemplate add, and how do you handle send failures?
KafkaTemplate wraps Kafka producer operations and integrates them with Spring-managed producer configuration. Its send methods return CompletableFuture<SendResult<K, V>>, allowing you to observe completion without immediately blocking.
Save this constructor-injected service as KafkaProducerService.java in the same package. It logs asynchronous outcomes and returns failures to its caller rather than swallowing them. The catch also converts synchronous send failures into failed futures.
package com.example.kafka;
import java.util.concurrent.CompletableFuture;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.kafka.core.KafkaTemplate;
import org.springframework.kafka.support.SendResult;
import org.springframework.stereotype.Service;
@Service
public class KafkaProducerService {
private static final Logger log =
LoggerFactory.getLogger(KafkaProducerService.class);
private final KafkaTemplate<String, String> kafkaTemplate;
public KafkaProducerService(KafkaTemplate<String, String> kafkaTemplate) {
this.kafkaTemplate = kafkaTemplate;
}
public CompletableFuture<SendResult<String, String>> sendMessage(
String topic, String key, String message) {
try {
return kafkaTemplate.send(topic, key, message)
.whenComplete((result, error) -> {
if (error != null) {
log.error("Kafka send failed for topic {}", topic, error);
} else {
log.info("Published to {} partition {} offset {}",
topic,
result.getRecordMetadata().partition(),
result.getRecordMetadata().offset());
}
});
} catch (RuntimeException error) {
log.error("Kafka send failed for topic {}", topic, error);
return CompletableFuture.failedFuture(error);
}
}
}A successful future reports the producer-side send outcome according to its acknowledgement configuration. It does not confirm listener execution, a database commit, or completion of a business workflow.
6. How do acknowledgements, retries, and idempotence differ?
acks=0does not wait for a broker acknowledgement.acks=1waits for the leader, but not follower acknowledgements.acks=allwaits for the in-sync replicas.- Producer retries resend requests after retryable delivery failures. Prefer controlling the delivery budget with
delivery.timeout.msinstead of blindly increasing retry counts. - Producer idempotence prevents duplicates caused by producer retries; it does not deduplicate independent application-level sends or repeated consumer side effects.
In the selected client, idempotence is enabled by default unless conflicting settings disable it. It requires acks=all, retries greater than zero, and max.in.flight.requests.per.connection no greater than five. The example enables it explicitly so incompatible settings cause a configuration error.
Interview trap: acks=all does not create extra replicas. Durability also depends on replication and min.insync.replicas, the minimum in-sync replica count required for an acknowledged write with acks=all.
Consumer Interview Questions: Groups, Containers, and Offsets
7. How does @KafkaListener receive a message?
The annotation identifies a method on a Spring-managed bean. Boot’s default container factory supplies the listener infrastructure, while the configured deserializer produces the value passed to the method. Save this as KafkaConsumerService.java:
package com.example.kafka;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.kafka.annotation.KafkaListener;
import org.springframework.stereotype.Component;
@Component
public class KafkaConsumerService {
private static final Logger log =
LoggerFactory.getLogger(KafkaConsumerService.class);
@KafkaListener(topics = "myTopic",
groupId = "interview-demo", concurrency = "3")
public void processMessage(String content) {
// Replace with business processing; let failures propagate.
log.info("Received a message containing {} characters", content.length());
}
}Consumers sharing a group divide the subscribed partitions. A different group can consume the same topic independently. Within a subscribing consumer group, each partition is assigned to one consumer at a time.
The configured earliest reset policy applies when no valid committed offset exists; it does not replay the entire topic on every restart. For more listener configuration, see the Spring Boot Kafka consumer guide.
8. How do the two listener containers differ?
KafkaMessageListenerContainer runs a single consumer thread for its configured subscription or explicit partition assignment. ConcurrentMessageListenerContainer delegates to multiple child containers, each with its own consumer. Neither guarantees that an individual consumer receives every partition.
Normally, configure concurrency through the listener container factory or the annotation, rather than constructing containers manually. The example requests three consumers per application instance. Useful partition-level parallelism remains bounded by the partitions assigned across the whole group.
For a separate three-partition topic, four consumers in one subscribing group can have an assignment like this:
Topic partitions Consumer group
P0 ------------------> Consumer A
P1 ------------------> Consumer B
P2 ------------------> Consumer C
Consumer D: idleConcurrency is not a promise of equal workload: partition assignment and traffic distribution matter. The same listener instance is invoked by multiple consumer threads, so keep it stateless or otherwise thread-safe.
9. What are offsets and acknowledgement modes?
An offset identifies a record’s position within a partition. A committed offset records where the group should resume; it represents the next record to consume, not the last processed record.
With auto-commit disabled and no transactions, the container’s acknowledgement mode controls commit timing. Spring Kafka’s default is BATCH; the example explicitly selects RECORD. The important modes are:
| Mode | Commit behavior |
|---|---|
RECORD | Commit after the record listener successfully processes a record. |
BATCH | Commit after all records returned by a poll have been processed. |
MANUAL | The listener acknowledges explicitly; commits then follow batch-style timing. |
MANUAL_IMMEDIATE | Commit immediately when acknowledgement happens on the consumer thread; otherwise acknowledgements are queued. |
Processing successfully and then crashing before the offset commit can cause redelivery. Make side effects safe to repeat; choosing manual acknowledgement alone does not eliminate that failure window.
Failure-Handling and Delivery Scenarios
10. How do you configure listener retries and a dead-letter topic?
For a non-transactional record listener, use a container-level DefaultErrorHandler with a backoff and a recoverer. Boot associates a CommonErrorHandler bean with its default factory. The annotation’s errorHandler attribute instead selects a listener-level handler; it is not interchangeable with a container retry policy.
Add this complete KafkaErrorConfiguration.java. It explicitly routes exhausted records to myTopic.DLT, preserving their partition number.
package com.example.kafka;
import org.apache.kafka.clients.admin.NewTopic;
import org.apache.kafka.common.TopicPartition;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.kafka.config.TopicBuilder;
import org.springframework.kafka.core.KafkaTemplate;
import org.springframework.kafka.listener.CommonErrorHandler;
import org.springframework.kafka.listener.DeadLetterPublishingRecoverer;
import org.springframework.kafka.listener.DefaultErrorHandler;
import org.springframework.util.backoff.FixedBackOff;
@Configuration(proxyBeanMethods = false)
public class KafkaErrorConfiguration {
@Bean
public NewTopic deadLetterTopic() {
return TopicBuilder.name("myTopic.DLT")
.partitions(10).replicas(1).build();
}
@Bean
public CommonErrorHandler kafkaErrorHandler(
KafkaTemplate<String, String> template) {
var recoverer = new DeadLetterPublishingRecoverer(template,
(record, error) -> new TopicPartition(
record.topic() + ".DLT", record.partition()));
recoverer.setFailIfSendResultIsError(true);
return new DefaultErrorHandler(
recoverer, new FixedBackOff(1000L, 2L));
}
}- For retryable listener failures, this backoff permits two retries after the initial attempt, separated by one second.
- Fatal classifications, including deserialization and message-conversion exceptions, skip retries and go directly to recovery.
- The DLT has matching partitions because the resolver preserves the original partition. Waiting for the DLT send result makes publishing failures throw instead of silently counting as recovery.
- With the shown record-acknowledgement setup, successful recovery permits progress past the failed record. A recovery exception causes redelivery rather than successful recovery.
Long delays may justify non-blocking retry topics through @RetryableTopic, but forwarding records to retry topics sacrifices the original topic’s ordering guarantees. Choose that tradeoff deliberately.
11. What if deserialization fails before the listener runs?
A listener’s try/catch cannot catch a failure that happens before invocation. ErrorHandlingDeserializer delegates to the actual deserializer and exposes failures to container error handling. If you publish those failures to a DLT, its producer must also support the original raw byte values; the string-only producer above is not a general JSON deserialization-recovery configuration.
12. Does Spring Boot Kafka provide exactly-once processing?
Not automatically. Kafka transactions can commit produced records and consumed offsets together for a Kafka read-process-write sequence. Downstream consumers need read_committed isolation to exclude aborted transactional records. That guarantee does not make an unrelated database write or HTTP call atomic with Kafka.
A strong interview answer separates producer idempotence, consumer redelivery, transactional Kafka output, and external business side effects rather than calling all four “exactly once.”
Production Checklist
- Provision deliberately: review topic partitions, replication, retention, and access permissions outside ordinary application deployments.
- Secure connections: use appropriate encryption, authentication, and least-privilege authorization; keep credentials outside source code.
- Budget processing time: keep processing and blocking retry delays compatible with
max.poll.interval.ms; exceeding the polling interval can trigger consumer-group reassignment. - Observe failures: monitor lag, send failures, retry activity, and DLT arrivals. Assign ownership for investigating and replaying dead-letter records.
- Test recovery: exercise broker outages, duplicate delivery, listener exceptions, and DLT publishing failures. Start with these Spring Kafka testing examples.
FAQ
How does Spring Boot create Kafka topics with NewTopic?
Declare a NewTopic bean in a scanned configuration class. Boot’s KafkaAdmin processes that declaration during startup when administrative topic creation is enabled and the cluster permits the operation.
Does KafkaAdmin automatically delete topics?
No. Removing a NewTopic bean does not delete the existing topic. Deletion requires an explicit administrative operation and appropriate cluster permissions.
What is the difference between KafkaTemplate and a Kafka producer?
KafkaTemplate is Spring’s abstraction over Kafka producer operations. It uses configured producer infrastructure and exposes asynchronous send results through CompletableFuture.
How does listener concurrency relate to Kafka partitions?
Concurrency controls the number of child consumers created for a listener container. In a subscribing consumer group, each partition is assigned to one consumer at a time, so consumers beyond the available partitions do not increase partition-level parallelism.
How do you configure retries and a dead-letter topic for @KafkaListener?
Configure a container-level DefaultErrorHandler with a backoff and DeadLetterPublishingRecoverer. Provision its destination topic, classify non-retryable exceptions, and ensure DLT publishing failures are observable rather than treated as successful recovery.
Further Reading
- Spring Boot Kafka support — auto-configuration and application integration.
- Boot-managed dependency coordinates — the versions selected by dependency management.
- Spring Kafka topic configuration — NewTopic declarations and administration.
- Sending with KafkaTemplate — send methods and asynchronous results.
- Kafka producer configuration — acknowledgements, retries, and idempotence.
- Listener containers and offset commits — concurrency and acknowledgement modes.
- Spring Kafka exception handling — retries, recovery, and dead-letter publishing.
- Serialization and deserialization — JSON configuration and pre-listener failures.
