Demystifying Spring WebFlux (Project Reactor -Engine of Spring WebFlux)
In the second part of our WebFlux series, we dive into the engine that powers Spring WebFlux — Project Reactor. If you haven’t covered the…
Demystifying Spring WebFlux (Project Reactor -Engine of Spring WebFlux)

In the second part of our WebFlux series, we dive into the engine that powers Spring WebFlux — Project Reactor. If you haven’t covered the basics of WebFlux yet, I recommend checking out the previous part, Demystifying Spring WebFlux,
Now, let’s start with the fundamentals. First question first: What is Project Reactor?
As per the definition, Project Reactor is an implementation of the Reactive Streams specification that provides:
- Non-blocking async processing
- Backpressure support
- Functional-style data pipelines
- Event-driven programming model
Hmm 🤔 but now what is this Reactive Streams specification ?
In simple terms, Reactive Streams is a standard for asynchronous stream processing with non-blocking backpressure
👉 It defines how publishers and subscribers communicate safely in async systems.
But What is the Funda of all these Project Reactor and Reactive Programming 🧐
At its core, reactive programming (or Reactive Streams) follows the Observer Design Pattern — a behavioral pattern that defines a one-to-many dependency. In this model, a Subject (publisher) automatically notifies Observers (subscribers/listeners) whenever its state changes.
Basically we are saying hey I have submitted some tasks let’s say the DB call notify me when the response is available
Reactive Streams has 4 core components.
1️⃣ Publisher
👉 Produces data: e.g Database, Kafka Producer
public interface Publisher<T> {
void subscribe(Subscriber<? super T> s);
}
2️⃣ Subscriber
👉 Consumes data
onSubscribe()
onNext()
onError()
onComplete()
3️⃣ Subscription (Backpressure Controller)
🔥 MOST IMPORTANT CONCEPT
Acts like a contract between publisher and subscriber.
Subscriber requests data via:
subscription.request(n);
It is basically saying hey publisher at a time provide me only n items
4️⃣ Processor (Optional)
👉 Acts as both:
- Subscriber
- Publisher
Used for transformations
Publisher
↓
Subscription (backpressure)
↓
Subscriber
Now Let’s look How Project Reactor Implements Publisher and Subscriber
Now that we understand the Reactive Streams concepts, let’s see how Project Reactor actually implements them.
🟢 Publisher in Project Reactor
In Project Reactor, the Publisher is represented by two core types:
- Mono → emits 0 or 1 item
- Flux → emits 0 to N items
These are the primary building blocks you work with when creating reactive pipelines.
🟣 Subscriber in Project Reactor
In most real-world scenarios, you don’t implement the Subscriber interface yourself.
Instead:
- Reactor provides the internal Subscriber implementation
- You typically pass a Consumer using
subscribe() - Reactor wires everything together behind the scenes
👉 This is why reactive code often looks very concise.
and
🔵 Processor Role via Operators
Reactive Streams defines a Processor (both Publisher + Subscriber).
In Project Reactor, this role is effectively played by operators such as:
map()flatMap()filter()buffer()
These operators sit between the source and the final subscriber, transforming the data as it flows through the pipeline.
🚀 Example: Understanding Mono vs Flux in Action
Let’s look at a simple example to better understand how Flux (Publisher) and the Subscriber work together in Project Reactor.
import reactor.core.publisher.Flux;
import java.time.Duration;
public class ReactiveExample {
public static void main(String[] args) throws InterruptedException {
ReactiveExample obj= new ReactiveExample();
System.out.println("Current thread "+Thread.currentThread().getName());
obj.consumeNos();
System.out.println("After consumer call Current thread "+Thread.currentThread().getName());
Thread.sleep(5000);
}
public Flux<Integer> getStreamOfNo(){
return Flux.just(1,2,3,4,5);
}
public void consumeNos(){
getStreamOfNo()
.delayElements(Duration.ofSeconds(1))
.doOnNext(no->{
System.out.println("Consumer running on thread "+Thread.currentThread().getName()+" "+no);
})
.subscribe();
}
}
🧩 What’s Happening Here?
**getStreamOfNo()acts as the Publisher**, emitting a stream of numbers usingFlux.**consumeNos()acts as the Subscriber**, consuming the emitted values.**delayElements()** makes the stream asynchronous by introducing a delay.**doOnNext()** is an operator that lets us peek into the stream.**subscribe()** triggers the reactive pipeline.
⏱️ Why Do We Need Thread.sleep(5000)?
Notice that the processing is asynchronous.
Because of delayElements():
- The main thread does not wait for the stream to finish.
- If we remove
Thread.sleep(5000), the main thread will exit early - As a result, the reactive pipeline may not complete.
👉 In simple terms:
The Publisher is slow (1-second delay per element), so we keep the JVM alive using
sleep().
⚠️ Important: In real reactive applications (like Spring WebFlux), you typically do NOT use Thread.sleep() — the runtime manages the lifecycle for you.
🔍 What You’ll Notice in the Output
- Main thread prints immediately
- Reactive processing happens on a different thread
- Values are printed with delay
- Demonstrates non-blocking async behavior
Current thread main
After consumer call Current thread main
Consumer running on thread parallel-1 1
Consumer running on thread parallel-2 2
Consumer running on thread parallel-3 3
Consumer running on thread parallel-4 4
So that is the basic working and idea about the Project Reactor and its Publisher Mono and Flux
🔹 How Spring WebFlux Uses Project Reactor
Spring WebFlux is built on top of Project Reactor.
👉 Controller return types in WebFlux are:
Mono<T>Flux<T>
Instead of:
TList<T>
🔸 Flow in Spring WebFlux (Reactive)
Client → Controller → Service → DB
(non-blocking) ✅
The thread is released while waiting, as we have seen in above code that reactor processing runs on different thread instead of Main thread and whenever the response is available it is being assigned to any thread which is free as we have seen in the output as all values are being consumed by different thread
@GetMapping("/user/{id}")
public Mono<User> getUser(@PathVariable String id) {
return userService.findById(id);
}
With this, we come to the end of Part 2 of our Demystifying Spring WebFlux series. Understanding Project Reactor and its core Publisher types — Mono and Flux — is absolutely crucial, because the entire WebFlux ecosystem is built on top of these two abstractions.
In the next part, we’ll dive into practical examples, best practices, and — equally important — where you should and should not use WebFlux. We’ll also cover key interview questions to help you stay ahead.
Stay tuned — the real fun begins next! 🚀
메타데이터
- post_id
- 5dff2735a396
- slug
- demystifying-spring-webflux-project-reactor-engine-of-spring-webflux-5dff2735a396
- url
- https://medium.com/@write2farrukhmasroor/demystifying-spring-webflux-project-reactor-engine-of-spring-webflux-5dff2735a396
- canonical_url
- https://medium.com/@write2farrukhmasroor/demystifying-spring-webflux-project-reactor-engine-of-spring-webflux-5dff2735a396
- author_url
- https://medium.com/@write2farrukhmasroor
- status
- ok
- fetched_at
- 2026-08-17 16:17:32