DZone
Thanks for visiting DZone today,
Edit Profile
  • Manage Email Subscriptions
  • How to Post to DZone
  • Article Submission Guidelines
Sign Out View Profile
  • Post an Article
  • Manage My Drafts
Over 2 million developers have joined DZone.
Log In / Join
Refcards Trend Reports
Events Video Library
Refcards
Trend Reports

Events

View Events Video Library

Related

  • End-to-End Event Streaming With Kafka, Spring Boot and AWS SQS/SNS (Production-Ready Code Guide)
  • Reactive Event Streaming Architecture With Kafka, Redis Streams, Spring Boot, and HTTP Server-Sent Events (SSE)
  • Competing Consumers With Spring Boot and Hazelcast
  • Reactive Kafka With Streaming in Spring Boot

Trending

  • Optimizing High-Volume REST APIs Using Redis Caching and Spring Boot (With Load Testing Code)
  • What Nobody Tells You About Multimodal Data Pipelines for AI Training
  • Zone-Free Angular: Unlocking High-Performance Change Detection With Signals and Modern Reactivity
  • The Third Culture: Blending Teams With Different Management Models
  1. DZone
  2. Software Design and Architecture
  3. Microservices
  4. Evolving Spring Boot APIs to an Event-Driven Mesh

Evolving Spring Boot APIs to an Event-Driven Mesh

Learn to transform Spring Boot REST APIs into an event-driven architecture by utilizing Kafka, RabbitMQ, or NATS to enhance scalability, resilience, and responsiveness.

By 
Lavi Kumar user avatar
Lavi Kumar
·
May. 05, 26 · Analysis
Likes (1)
Comment
Save
Tweet
Share
1.3K Views

Join the DZone community and get the full member experience.

Join For Free

Overview

As modern applications require greater scalability, resilience, and responsiveness, traditional REST-based architectures are hitting their limits. This article looks into how Spring Boot developers can upgrade their APIs from synchronous REST calls to asynchronous, event-driven communication through an event mesh that utilizes technologies like Kafka, RabbitMQ, or NATS. 

It emphasizes important architectural differences, design patterns for decoupling services, and practical implementation strategies in Spring Boot. Readers will discover how to integrate event streams, manage eventual consistency, and achieve real-time responsiveness while ensuring observability and fault tolerance. The article also covers trade-offs, performance improvements, and best practices for moving enterprise APIs towards event-driven systems.

This article provides a practical guide for transforming Spring Boot services from synchronous REST to an event-driven architecture using an event mesh. It explains the reasons for this transition by highlighting the limitations of REST in terms of scaling and resilience — such as latency chains, tight runtime coupling, and failure propagation—and compares these issues with the benefits of the mesh’s asynchronous pub/sub structure that can handle bursts, separates producers from consumers, and enables real-time experiences. 

Utilizing Java 21, Spring Boot 3, Gradle, and Kafka for clarity (with additional notes for RabbitMQ and NATS), the article outlines a working example: a REST endpoint that sends out OrderCreated events; independent consumers (Payment, Notification) that respond idempotently; retries and dead-letter topics that manage failures; and Micrometer/OpenTelemetry that offer tracing across producer/consumer boundaries.

REST vs. event-driven

It covers schema governance (transitioning from JSON to Avro/Protobuf with a registry), choices regarding partitioning and ordering, and the trade-offs involved with exactly-once semantics. A migration playbook (starting with publish-first, using the strangle pattern, reinforcing with DLT/metrics, and then scaling while phasing out fan-out REST calls) allows for gradual adoption without needing a complete rewrite. Docker/Tescontainers snippets facilitate local execution and testing.

The outcome is a practical guide for modernizing APIs: maintain REST where it is suitable, emit domain events as the core integration mechanism, and develop a governed, observable event mesh to enhance scalability, resilience, and responsiveness.

Introduction: Moving Beyond REST

REST is straightforward, widely used, and excellent for handling request/response interactions. However, as systems grow, synchronous connections can create issues:

  • Latency chains (a single slow dependency can delay the entire request)
  • Tight runtime coupling (all services need to be operational at the same time)
  • Sudden spikes in load and cascading failures

Event-driven architectures (EDAs) and event meshes help separate producers from consumers and promote asynchronous, streaming communication, which enhances scalability, resilience, and real-time user experience.

This article will demonstrate how to transform a Spring Boot service from REST to an event-driven model using an event mesh (with a Kafka demo; notes on RabbitMQ/NATS are also included). We will discuss design patterns, schema/versioning, retries/idempotency, observability, and tips for migration, along with runnable code.

What Is an Event Mesh?

An event mesh is a distributed system that links event producers and consumers across different services, regions, and runtimes. Rather than depending on fixed endpoints, an event mesh routes events dynamically using topics, subjects, or keys, which enables services to communicate without being tightly connected.

An event mesh offers:

  • Smart routing across boundaries (topics/subjects, not URLs)
  • Horizontal scalability with built-in buffering for handling traffic spikes
  • Pub/sub and stream processing that separates producers from consumers
  • Global reach, allowing events to move across clusters, clouds, and geographical areas

How it differs from a single broker:

A traditional broker is usually local — limited to one cluster, one region, one namespace. An event mesh covers multiple brokers or clusters, providing unified discovery, routing, replication, and governance. You can think of it as a global data bus instead of just a single local queue or topic.

Event-Driven APIs in Spring Boot

Spring Boot offers excellent support for creating event-driven APIs:

  • Kafka: using spring-kafka for producers, consumers, and listener containers
  • RabbitMQ: utilizing spring-amqp with RabbitTemplate and @RabbitListener
  • NATS: through community starters or the official io.nats:jnats client

Example flow:

  • OrderService manages a REST POST and publishes an OrderCreated event.
  • PaymentService takes in the event and processes payments in an asynchronous manner.
  • NotificationService listens for the same event to send out emails or alerts.

REST and events work well together — your HTTP endpoint can give an immediate response while the more complex tasks are handled asynchronously in the background.

REST and events working together

Advantages: Why Transition From REST to Events?

Switching from REST to an event-driven architecture significantly enhances system performance during high loads and failures. REST relies on synchronous, direct communication, which can lead to bottlenecks and tight interdependencies. 

In contrast, events facilitate asynchronous flow control, enabling services to scale independently and manage traffic surges through queues and streams. Failures are no longer interconnected — if a consumer is slow or offline, messages can be safely stored with retry and backoff strategies. This architecture also supports real-time functionalities: as soon as an event happens, downstream systems, analytics processes, and user interfaces get updates instantly. In summary, events foster a more efficient, responsive, and robust ecosystem that adapts smoothly to business needs.

  • Scalability and performance: Asynchronous buffering, horizontal consumers, built-in back-pressure.
  • Resilience: Loose coupling; failures are contained; retries, DLQ, and parked messages enhance stability.
  • Real-time delivery: Send updates to clients through WebSockets/SSE, directly powered by event streams.

Key Points of Implementation (Code)

We will utilize a single Spring Boot application to demonstrate the main patterns from start to finish:

REST → Event:

  • A straightforward POST /orders endpoint checks the input, saves the order, and sends an OrderCreated event to Kafka using KafkaTemplate.

Kafka listeners (Payment and notification):

  • Two logical consumers (like PaymentListener and NotificationListener) listen to the order-created topic and respond asynchronously — charging the customer, updating the status, sending emails, and more.

Reliability: Retries, DLT, idempotency, tracing:

  • Spring Kafka error handlers for retries and dead-letter topics (DLT)
  • Idempotent consumers using a processed-event table or business keys
  • Tracing through trace IDs in headers and Spring Observability / OTEL

RabbitMQ/NATS notes:

  • The same process can be carried out with RabbitMQ (using spring-amqp, exchanges, and DLX for dead letters) or NATS/JetStream (subjects plus durable consumers) by changing the messaging layer while maintaining the same domain events and handler structure.

Project Setup (Gradle, Java 21)

Groovy
 
settings.gradle
rootProject.name = "orders-event-mesh"

build.gradle


Project setup

RabbitMQ note: Replace spring.kafka.* with spring.rabbitmq.* and use spring-boot-starter-amqp plus @RabbitListener/RabbitTemplate.

NATS note: Use io.nats:jnats, configure a Connection bean, and publish/subscribe with subjects. Spring wrappers are community-provided.

REST → Event Producer

OrderController.java


PaymentListener.javaPaymentListener.java

NotificationListener.javaNotificationListener.java

Local Run (Kafka)

Use Docker for Kafka (or Testcontainers in tests).

Run:

Dockerfile
 
docker compose up -d

./gradlew bootRun


Test the flow:

Shell
 
curl -X POST http://localhost:8080/api/orders \
  -H "Content-Type: application/json" \
  -d '{"orderId":"o-123","userId":"u-9","amount":42.35,"currency":"USD"}'


You should see consumer logs for payment/notification. Check DLT behavior by throwing a controlled exception in a listener.

Consumer logs for payment/notificatio

Check DLT behavior


Key Takeaways

  • REST alone restricts scalability and resilience: REST is effective for straightforward request/response interactions, but synchronous calls introduce latency, create tight runtime dependencies, and cause cascading failures under high load. As applications grow, REST can become a limiting factor since every service needs to reply instantly, which results in slowdowns and instability during peak times or outages.
  • Event mesh enables distributed and decoupled communication: An event mesh directs events between services, regions, and clusters by utilizing topics rather than fixed endpoints. It offers a worldwide pub/sub framework that can handle spikes, scale horizontally, and separate producers from consumers, allowing for robust, location-independent, real-time communication that goes beyond just one broker or local queue.
  • REST and events can work together: Embrace a publish-first approach; you don’t have to completely rewrite modern Spring Boot systems. You can maintain your current REST endpoints while also publishing domain events for important processes (like OrderCreated). This way, consumers can handle tasks asynchronously. It helps to lessen REST fan-out, boosts responsiveness, and allows for gradual migration using the Strangler pattern, all without causing issues for current clients.
  • Reliability needs idempotency, retries, and DLT: Event delivery happens at least once, which means consumers have to manage duplicates carefully. Systems that are ready for production require idempotent operations, backoff retries, dead-letter topics/queues (DLT), and tracing to see failures. These features help avoid duplicate charges, inconsistent states, and lost messages when there are outages or errors in consumer processing.
  • Schema evolution and observability support scalability: To scale events effectively, you need solid governance, not just messaging middleware. Schema registries like Avro and Protobuf ensure backward compatibility, while OpenTelemetry monitors asynchronous flows between services. Partitioning strategies help maintain order when necessary and allow for horizontal scaling, which makes event systems easier to manage, track, and secure for business expansion.

Conclusion

Transitioning from synchronous REST to an event mesh brings major benefits in scalability, resilience, and real-time responsiveness. With tools like Spring Boot and message brokers such as Kafka, RabbitMQ, or NATS, teams can publish domain events from their current REST workflows, handle tasks asynchronously with idempotency and retries, and ensure strong observability through tracing and metrics. Schema registries help ensure safe evolution as services develop. Implement the model gradually, track the performance and user experience enhancements, and grow the event mesh as your platform and organization mature.

References

GitHub Codebase: https://github.com/lavi2088/orders-event-mesh

REST Event kafka Spring Boot

Opinions expressed by DZone contributors are their own.

Related

  • End-to-End Event Streaming With Kafka, Spring Boot and AWS SQS/SNS (Production-Ready Code Guide)
  • Reactive Event Streaming Architecture With Kafka, Redis Streams, Spring Boot, and HTTP Server-Sent Events (SSE)
  • Competing Consumers With Spring Boot and Hazelcast
  • Reactive Kafka With Streaming in Spring Boot

Partner Resources

×

Comments

The likes didn't load as expected. Please refresh the page and try again.

  • RSS
  • X
  • Facebook

ABOUT US

  • About DZone
  • Support and feedback
  • Community research

ADVERTISE

  • Advertise with DZone

CONTRIBUTE ON DZONE

  • Article Submission Guidelines
  • Become a Contributor
  • Core Program
  • Visit the Writers' Zone

LEGAL

  • Terms of Service
  • Privacy Policy

CONTACT US

  • 3343 Perimeter Hill Drive
  • Suite 215
  • Nashville, TN 37211
  • [email protected]

Let's be friends:

  • RSS
  • X
  • Facebook