This content originally appeared on DEV Community and was authored by Thales
General Introduction
What is Reactive Programming?
Reactive programming is a declarative programming paradigm focused on data streams and the propagation of change. It allows working with both static (e.g. arrays) and dynamic (e.g. event emitters) data flows, automatically handling updates via the Observer pattern.
In essence, reactive programming is about data flow, asynchronous communication, and automatic propagation of changes.
In Spring, the key difference between traditional Spring MVC and WebFlux is synchronous vs asynchronous processing. Instead of blocking to wait for a response, reactive code allows you to invoke a method and keep doing other work while waiting.
Spring uses Project Reactor internally, which implements the Reactive Streams Specification.
Reactive Streams Specification
The Reactive Streams API consists of the following components:
- Publisher
- Subscriber
- Subscription
- Processor
Publisher
interface Publisher<T> {
fun subscribe(subscriber: Subscriber<in T>)
}
A Publisher
emits elements — but only on demand, meaning a Subscriber
must request items.
Subscriber
interface Subscriber<T> {
fun onSubscribe(subscription: Subscription)
fun onNext(t: T)
fun onError(t: Throwable)
fun onComplete()
}
Handles emitted data, errors, and stream completion.
Subscription
interface Subscription {
fun request(n: Long)
fun cancel()
}
Controls data flow (backpressure). A Subscriber
uses this to request elements.
Processor
interface Processor<T, R> : Subscriber<T>, Publisher<R>
Transforms a stream — acts as both subscriber and publisher.
In practice, we don’t implement these interfaces manually—that would be a lot of work. Instead, we use libraries that already implement them. One such library is Project Reactor, which implements the Reactive Streams Specification and is part of the Spring WebFlux module. It uses classes like Flux and Mono, which act as publishers or subscribers.
Project Reactor
Why use Reactor?
- Avoids thread blocking during I/O.
- Non-blocking by default → better resource usage.
- Ideal for high concurrency systems (e.g., Black Friday sales).
Reactor is event-loop based: requests go into the loop and get picked up asynchronously.
Spring WebFlux
Spring WebFlux is the reactive web stack introduced in Spring 5.0.
- Fully non-blocking
- Supports backpressure
- Can run on Netty or Servlet containers (3.1+)
WebFlux works with two main types from Reactor:
Type | Description |
---|---|
Mono | Emits 0 or 1 item |
Flux | Emits 0 to N items |
Operators: Mono & Flux
Mono
Mono.just("data")
Emits a single item and completes.
Flux
Flux.just("a", "b", "c")
Emits multiple items, one after another.
Timeline representation
- Black line: stream completed
- Red X: error occurred
To find methods that best suit your needs, follow the guide below:
Common Methods in Kotlin
.map()
Transforms value inside Mono/Flux.
Mono.just("5")
.map { it.toInt() }
.flatMap()
Transforms and flattens nested streams.
Mono.just("5")
.flatMap { id -> getUserById(id) }
Hands-On: Project
- Build reactive pipelines
- Chain operators
- Handle exceptions properly
Error Handling in Streams
In reactive streams, errors are terminal unless explicitly handled.
Common patterns:
.onErrorResume { Mono.just(fallbackValue) }
.onErrorReturn(defaultValue)
Uncaught exceptions may throw UnsupportedOperatorException
or other runtime errors.
Functional Endpoints
Prefer separating routing from logic using functional endpoints.
Router
val route = coRouter {
accept(APPLICATION_JSON).nest {
GET("/person/{id}", handler::getPerson)
GET("/person", handler::listPeople)
}
POST("/person", handler::createPerson)
}
Handler
class PersonHandler(private val repository: PersonRepository) {
suspend fun listPeople(request: ServerRequest): ServerResponse { ... }
suspend fun createPerson(request: ServerRequest): ServerResponse { ... }
suspend fun getPerson(request: ServerRequest): ServerResponse { ... }
}
The Four Pillars of Reactive Programming
Pillar | Meaning |
---|---|
Responsive | Reacts quickly to user actions |
Resilient | Recovers from failures |
Elastic | Scales with demand (multicore, cloud-native, etc.) |
Message-driven | Uses async communication and message passing |
Supporting Material & References
- Reactive Streams Spec
- Project Reactor Docs
- Spring WebFlux Error Handling
- Baeldung – Combine Streams
- Mono.zipWith Example
- Udemy Course
- YouTube Explanation (BR)
This content originally appeared on DEV Community and was authored by Thales