What is Reactive Programming? - Building "ReactiveUserService" (A reactive service managing users)
- coding z2m
- Jul 1
- 6 min read
💡 Reactive Programming is:
Asynchronous, non-blocking, event-driven programming with backpressure support, ideal for handling streaming data and concurrent workloads efficiently.
✅ 1. Asynchronous
Meaning:In asynchronous programming, tasks are not executed one after another. Instead, a task can start, and while it's waiting (e.g., for data from a server), the program continues doing other work.
Example:Imagine you're cooking dinner and the oven takes 30 minutes to heat. While waiting, you chop vegetables or wash dishes—you don’t just stand there. That's asynchronous behavior.
In code:Instead of waiting for a file to be read before continuing, your program starts the read and moves on to the next instruction, handling the result later when it's ready.
✅ 2. Non-blocking
Meaning:Non-blocking means a function does not stop the program's execution to wait for a result. It allows the system to stay responsive by not getting "stuck" on slow operations.
Example:Calling a friend and leaving a voicemail instead of waiting on the line indefinitely. You're not blocked—you go on with your day.
In code:If one function is fetching data from the internet, it doesn’t prevent other functions from running while waiting for the data.
✅ 3. Event-driven
Meaning:This style is centered around responding to events—like user clicks, messages from servers, or sensor input. You define what should happen when a specific event occurs.
Example:In a smart home system, if motion is detected (an event), then the lights turn on (a response).
In code:You register a "listener" or a "callback" for an event, and when the event happens, the corresponding function is executed.
✅ 4. Backpressure Support
Meaning:Backpressure is a mechanism to handle overload—when a system receives more data/events than it can process. It slows down or buffers data to avoid crashing or memory overuse.
Example:Imagine you're drinking from a faucet, but water comes out too fast. You can ask someone to turn down the flow. That’s backpressure: controlling the rate of input.
In code:A data stream can notify its source to pause or reduce the data rate so the consumer has time to catch up.
✅ Summary of Reactive Programming:
It’s a way to build responsive systems that can handle lots of events or data streams without freezing up, thanks to being asynchronous, non-blocking, event-driven, and smart about flow control (backpressure).
🔄 In Reactive Systems: These are core principles of Reactive Systems, which apply Reactive Programming to building robust applications.
🔄 1. “Data is pushed from the source to the subscriber”
What it means:
In reactive systems, the data producer (source) pushes data to the consumer (subscriber) as it becomes available.
The subscriber doesn’t keep asking (polling) for data—it just waits, and the system sends it new data automatically.
Example:
Think of YouTube subscriptions: You don’t ask every minute if there's a new video; YouTube pushes a notification when a new one is published.
In code: sourceObservable.subscribe((data) => {
console.log("Got new data:", data);
}); Here, data is pushed when available, not requested manually. 🔁 2. “Consumers react to new data”
What it means:
Consumers (like UI components, services, etc.) don’t control the flow—they simply react whenever data arrives.
This leads to automatic, responsive behavior.
Example:
Your email inbox updates when new mail arrives. It doesn’t ask for updates—it just reacts to the new email being delivered.
In code: observable.subscribe((message) => {
showNotification(message);
}); Whenever message arrives, showNotification() is triggered. 🌊 3. “Supports streaming, parallelism, and resilience”
Let’s break that into parts:
📺 a) Streaming
Data flows continuously like a stream, not in chunks or batches.
Useful for real-time systems like chat apps, stock tickers, or sensor networks.
Example: Think Netflix streaming—you're watching content as it downloads, not after the whole file is ready. 🧠 b) Parallelism
Reactive systems can process data in parallel, taking advantage of multi-core systems.
Different streams or parts of a stream can be handled by different threads or services.
Benefit: Increases throughput and performance.
Example: A video processing system can process video frames in parallel as they stream in.
🛡️ c) Resilience
Reactive systems are fault-tolerant. If part of the system fails (e.g., a service crashes), it can recover gracefully.
Using mechanisms like timeouts, retries, fallbacks, or circuit breakers.
Example: If a microservice crashes, the system might retry the request, send a cached response, or route to a backup server. ✅ Summary:
A reactive system pushes data to subscribers, which then react automatically. It’s built for continuous data streams, can scale across cores or machines, and is designed to recover from failures gracefully.
📊 Traditional vs Reactive Comparison
Feature | Traditional Java (Imperative) | Reactive Java (Declarative) |
Execution | Step-by-step, blocking | Asynchronous, non-blocking |
Thread usage | One thread per request | Fewer threads, event loop based |
Data flow | Pull (request → result) | Push (data → event) |
Error handling | try-catch | onErrorResume / retry |
Example | List<T> | Flux<T> or Mono<T> |
Libraries | JDBC, RestTemplate | R2DBC, WebClient, Project Reactor |
PART 2: Core Concepts: Mono<T> vs Flux<T>
Type | Meaning | When to Use |
Mono<T> | 0 or 1 result | For a single item or empty (like fetching a user by ID) |
Flux<T> | 0 to many results | For stream or list (like getting all users) |
Both are part of Project Reactor – the backbone of Spring WebFlux. Let's take a deep dive into the core concepts of Mono<T> and Flux<T> in the context of Project Reactor, which is the reactive foundation of Spring WebFlux. 🔧 What is Project Reactor?
Project Reactor is a fully non-blocking Reactive Programming library for the JVM, developed by Pivotal/VMware, and it's the backbone of Spring WebFlux (the reactive alternative to Spring MVC).
It implements the Reactive Streams Specification, meaning it:
Supports asynchronous data processing
Handles backpressure
Works with data streams
🧱 Key Building Blocks in Reactor:
Mono<T> → 0 or 1 item
Flux<T> → 0 to N items (possibly infinite)
🟦 Mono<T>: Think “Maybe one”
🔍 Definition:
Mono<T> is a Publisher that emits 0 or 1 item and then completes (or fails).
Use Mono<T> when:
You expect a single value (or none), such as:
A user record from a database
An HTTP response body
A calculation result
✅ Example: Mono<String> nameMono = Mono.just("Alice");
nameMono.subscribe(name -> System.out.println("Hello, " + name));
💥 Error case: Mono.error(new RuntimeException("Something went wrong"))
.subscribe(
val -> System.out.println(val),
err -> System.err.println("Error: " + err.getMessage())
);
🟩 Flux<T>: Think “A stream of many”
🔍 Definition:
Flux<T> is a Publisher that emits 0 to many items, possibly infinite, and then completes (or fails).
Use Flux<T> when:
You expect multiple items, such as:
A list of products from a DB
Live events from a WebSocket
A stream of sensor readings
✅ Example:
Flux<Integer> numbers = Flux.just(1, 2, 3, 4, 5);
numbers.subscribe(num -> System.out.println("Got number: " + num)); ♾️ Infinite Flux (with interval): Flux.interval(Duration.ofSeconds(1))
.subscribe(n -> System.out.println("Tick: " + n));
🔄 Mono vs Flux: Side-by-side
Feature | Mono<T> | Flux<T> |
Emits | 0 or 1 value | 0 to many values |
Completion | Completes after emitting or no item | Completes after all items or infinite |
Use case | Single item APIs (e.g., GET /user) | Streams, collections, updates |
Example | DB query for one user | Stream of chat messages |
🔗 How They Power Spring WebFlux
Spring WebFlux is Spring’s non-blocking, reactive web framework built on top of Project Reactor. It uses Mono and Flux as return types in controller methods.
Example: Mono in WebFlux Controller
@GetMapping("/user/{id}")
public Mono<User> getUser(@PathVariable String id) {
return userService.findUserById(id); // returns Mono<User>
}
Example: Flux in WebFlux Controller @GetMapping("/users")
public Flux<User> getAllUsers() {
return userService.getAllUsers(); // returns Flux<User>
}
🧠 Advanced Concepts (Just a Peek)
Backpressure: Both Mono and Flux support it (in Flux, it's more relevant).
Operators: You can chain transformations (map, flatMap, filter) just like Java Streams.
Schedulers: Control execution context (publishOn, subscribeOn) to shift threads.
✅ Summary:
Concept | Mono | Flux |
Purpose | Handle a single result (or none) | Handle multiple results (or stream of data) |
Project | Part of Project Reactor (Spring WebFlux) | Part of Project Reactor (Spring WebFlux) |
Use Cases | DB fetch by ID, API response | Streaming data, paginated results |
Non-blocking? | ✅ Yes | ✅ Yes |
Reactive Streams | ✅ Yes (supports backpressure) | ✅ Yes (supports backpressure) |
Let's walk through a hands-on Spring Boot application (ReactiveUserService) in the live session that uses Project Reactor (Mono and Flux) in a REST API built with Spring WebFlux. 📦 What We'll Build
A simple reactive REST API for managing Users:
Endpoint | Return Type | Description |
GET /users | Flux<User> | Return all users |
GET /users/{id} | Mono<User> | Return a user by ID |
🧪 Step 5: Test the API 🧪 Try with curl or Postman:
Comments