BackendBench
Coffee

Unravel › Java concepts › Messaging and Kafka

Kafka

Spring Kafka @KafkaListener

Spring Kafka runs the poll loop for you.

Learn these first

At a glance

Mental model

Instead of writing the reader's loop yourself (open book, read a page, move the bookmark), you hire an assistant who does that and just hands you each page to deal with.

What happens, in order
  1. 1@KafkaListener(topics = "orders", groupId = "billing") tells Spring which topic and groupAt startup it builds a listener container: one or more consumer threads running the poll loop for you.
  2. 2For every record the container calls your method with the payload (and optionally the ConsumerRecord, Acknowledgment or headers)Your method contains only business logic.
  3. 3By default offsets are committed by the container after your method returns normally for the whole batch (AckMode.BATCH)If your method throws, the error handler decides: retry, skip, or send to a dead-letter topic.
  4. 4concurrency starts several consumer threads in the container, each a member of the group, up to the partition count
Remember
Watch out
Assuming a thrown exception retries forever (it is skipped after the default retries)Spawning threads from the listener so offsets are committed too earlyNot making the handler idempotentUsing the same groupId in two apps
Example (highlighted lines explain it)
@KafkaListener(topics = "orders", groupId = "billing")public void onOrder(String payload) {  service.handle(payload); // Spring polls, you just handle}
  1. line 1 uses KafkaListener, the core of Spring Kafka @KafkaListener
  2. line 3 Spring polls, you just handle
Read the full explanation (about 2 min)

Spring Kafka runs the poll loop for you. Annotate a method with @KafkaListener and Spring creates the consumer, polls in the background and calls your method once per record (or batch).

A mental model

Instead of writing the reader's loop yourself (open book, read a page, move the bookmark), you hire an assistant who does that and just hands you each page to deal with.

How it works

@KafkaListener(topics = "orders", groupId = "billing") tells Spring which topic and group. At startup it builds a listener container: one or more consumer threads running the poll loop for you.

For every record the container calls your method with the payload (and optionally the ConsumerRecord, Acknowledgment or headers). Your method contains only business logic.

By default offsets are committed by the container after your method returns normally for the whole batch (AckMode.BATCH). If your method throws, the error handler decides: retry, skip, or send to a dead-letter topic.

concurrency starts several consumer threads in the container, each a member of the group, up to the partition count.

Going deeper

The default error handler retries a failing record up to 10 times with no delay and then logs and skips it, which silently loses data unless you configure a DeadLetterPublishingRecoverer. Check this before trusting a listener in production.

Messages from one partition are handled one at a time, in order. Starting your own threads inside the method breaks that ordering and also breaks offset safety, because the container commits as soon as the method returns, not when your async work ends.

Because a record can be delivered more than once (rebalance, retry), the handler should be idempotent: handling the same order event twice must not charge a customer twice.

Under the hood

The container wraps a KafkaConsumer in a KafkaMessageListenerContainer running its own thread. A bean post-processor (KafkaListenerAnnotationBeanPostProcessor) scans beans for the annotation at startup and registers an endpoint for each annotated method.

Common mistakes

  • Assuming a thrown exception retries forever (it is skipped after the default retries).
  • Spawning threads from the listener so offsets are committed too early.
  • Not making the handler idempotent.
  • Using the same groupId in two apps.

How Unravel recognises it

When you paste code, Unravel looks for these signs of spring kafka @kafkalistener. Spotting them yourself is a good habit when you read unfamiliar code:

Part of a learning path

Related concepts

Builds on this

Frequently asked questions

What is Spring Kafka @KafkaListener?

Spring Kafka runs the poll loop for you. Annotate a method with @KafkaListener and Spring creates the consumer, polls in the background and calls your method once per record (or batch).

What are the most common mistakes with Spring Kafka @KafkaListener?

Assuming a thrown exception retries forever (it is skipped after the default retries). Spawning threads from the listener so offsets are committed too early. Not making the handler idempotent. Using the same groupId in two apps.

How can I see Spring Kafka @KafkaListener in real code?

Paste your own Java into Unravel and it will point out where spring kafka @kafkalistener appears, explain how it works at the detail level you choose, and draw the flow of the code around it.