Zum Hauptinhalt springen
Echtzeit-Radar & Feeds
Alle RSS Feeds ➔
👥 Community & Social
••••
Reverse EngineeringReverse-engineered 8BitDo firmware encryption(27.09.2026 um 01:18 Uhr)
••••
Sichere ProgrammierungHow Hindsight Turned Deployment #1017 Into the Fix for #1057(29.09.2026 um 06:25 Uhr)
••••••
Reverse EngineeringReverse-engineered 8BitDo firmware encryption(27.09.2026 um 01:18 Uhr)
••••
Sichere ProgrammierungHow Hindsight Turned Deployment #1017 Into the Fix for #1057(29.09.2026 um 06:25 Uhr)
••
Intelligence View
⚡ tsecurity.de Intelligence

Building a Clean Event Pipeline in Spring: From Simple Events to Async Listeners to the Outbox Pattern

Event‑driven architecture sounds simple on paper: “emit an event when something happens.” But once you start implementing it inside a real Spring Boot service, you quickly discover the hidden trade‑offs. In this post, we’ll walk through a …

0
↗ Quelle (dev.to)
Reagiere als Erste:r — dein Feedback zählt!

Event‑driven architecture sounds simple on paper: “emit an event when something happens.”


But once you start implementing it inside a real Spring Boot service, you quickly discover the hidden trade‑offs.



In this post, we’ll walk through a real‑world progression:




  • emitting domain events inside a service

  • handling them with @EventListener

  • realizing enrichment logic slows down the request

  • making listeners async

  • adding a production‑grade executor

  • and finally touching the gold standard: the Outbox Pattern



Let’s dive in.







1. The initial requirement: emit an event inside the service



Imagine a simple use case: when a user is created, we want to emit an event so other parts of the system can react.



A clean way to do this in Spring is to wrap ApplicationEventPublisher:




@Component
@AllArgsConstructor
public class UserEventPublisher {
private final ApplicationEventPublisher applicationEventPublisher;

public <T> void publish(T event) {
applicationEventPublisher.publishEvent(event);
}
}






Now inside your service:




userEventPublisher.publish(new UserCreatedEvent(userId, email));












2. Handling the event with @EventListener



A simple listener:




@Component
public class UserAuditListener {

@EventListener
public void handleUserCreateEvent(UserCreatedEvent event) {
System.out.println("User created: " + event);
}
}






This works beautifully… until you need to do more than just print.









3. The problem: enrichment logic slows down the request



Let’s say before publishing to Kafka, you want to:




  • fetch additional data from DB

  • call another service

  • enrich the event payload



Since @EventListener is synchronous by default, all this work blocks the original request thread.



Your API response time suddenly spikes.



Not good.









4. Making listeners async with @Async and @EnableAsync



Spring makes this easy:




@EnableAsync
@SpringBootApplication
public class App { }






And in the listener:




@Async
@EventListener
public void handleUserCreateEvent(UserCreatedEvent event) {
// runs in a background thread
}






Now the main request returns immediately while the listener does its work asynchronously.



But there’s a catch…









5. The default executor is not production‑grade



If you don’t configure anything, Spring uses SimpleAsyncTaskExecutor:




  • creates a new thread per task

  • no pooling

  • no backpressure

  • no monitoring



This is fine for demos, not for real systems.









6. Adding a custom executor



A better approach is to define your own thread pool:




@Configuration
@EnableAsync
public class AsyncConfig {

@Bean(name = "taskExecutor")
public Executor taskExecutor() {
return Executors.newCachedThreadPool();
}
}






Now all @Async methods use this executor.



You can replace it with a tuned ThreadPoolTaskExecutor for even more control.









7. The gold standard: the Outbox Pattern



Async listeners solve the latency problem, but they don’t solve the reliability problem.



What if:




  • the DB transaction commits

  • but the async listener fails before sending to Kafka?

  • or the service crashes?



You lose the event.



This is why mature systems use the Outbox Pattern.






How the Outbox Pattern works (high‑level)





  1. Write the event into an “outbox” table inside the same DB transaction




    • If the user is created, the outbox record is also created

    • Atomic, consistent, no partial failures




  2. A background process reads the outbox table


    This can be:




    • a scheduled Spring job

    • a Kafka Connect Debezium connector

    • a lightweight polling thread



  3. The background process publishes the event to Kafka


  4. After successful publish, the outbox record is marked as processed







Why this is the gold standard




  • no lost events

  • no double‑publishing

  • no dependency on async listeners

  • fully decoupled from request latency

  • battle‑tested at Uber, Netflix, Stripe, Shopify









8. Summary



Here’s the journey we walked through:




  • Start with simple Spring events

  • Add @EventListener to react to them

  • Realize enrichment logic slows down the request

  • Add @Async + @EnableAsync to make listeners non‑blocking

  • Add a custom executor for production‑grade async processing

  • Finally, adopt the Outbox Pattern for guaranteed delivery and reliability



This progression mirrors how real systems evolve as they scale.



If you’re building event‑driven microservices, the outbox pattern is the foundation you eventually want to reach.

Ähnliche Beiträge
🔍 Verwandte News

Auch interessante Nachrichten Building a Clean Event Pipeline in Spring: From Simple Events to Async Listeners to the Outbox Pattern

Thematisch verwandte Begriffe: Building, Clean, Event, Pipeline · 6 Treffer

Laden...

Videos werden geladen ...

Laden...

Beiträge werden geladen ...

Laden...

Videos werden geladen ...

Laden...

Beiträge werden geladen ...

Laden...

Videos werden geladen ...

Laden...

Beiträge werden geladen ...

Laden...

Videos werden geladen ...

Laden...

Beiträge werden geladen ...

Laden...

Videos werden geladen ...

💬 Kommentare werden geladen…
Zum Aktualisieren ziehen
ZERO-DAY CVE-2026-102367 | mall4j through 4.0 contains an insufficient session expiration vulnerab…
Advisory →
tsecurity.de Icon
Offline-Lesen, Eilmeldungen & 0ms Ladezeit

Installiere tsecurity.de direkt auf deinen Home-Bildschirm für das ultimative Vollbild-Magazinerlebnis ohne Browser-Leisten.

Nächster Beitrag