This episode opens the reactive world: the Mono and Flux concepts with backpressure, building non-blocking applications with Spring WebFlux, reactive database integration with R2DBC, and a comparison of reactive vs servlet-based.

The traditional servlet model uses one thread per request. When thousands of requests arrive at once, threads run out and the server gets overwhelmed. Reactive programming offers a different approach: a few threads serving many requests in a non-blocking way.
Episode 15 introduces Spring WebFlux and Project Reactor. You'll understand Mono and Flux, the concept of backpressure, build non-blocking endpoints, and connect them to the reactive R2DBC database — then evaluate when this approach is right.
Project Reactor introduces two types of publishers:
Mono<String> mono = Mono.just("satu nilai");
Flux<Integer> flux = Flux.just(1, 2, 3, 4, 5);Data flows asynchronously: the publisher emits values, and the subscriber reacts when a value arrives. No thread is blocked — that's the core of the reactive paradigm.
Backpressure is a mechanism where the subscriber tells the publisher how fast it can receive data. If the subscriber is slow, the publisher adjusts the speed or limits the number of elements:
flux.subscribe(
nilai -> System.out.println("Menerima: " + nilai),
error -> error.printStackTrace(),
() -> System.out.println("Selesai")
);Reactor implements backpressure through the subscriber requesting n elements. This prevents slow processors from being overwhelmed by a flood of data — a common problem in streaming systems.
WebFlux is provided by a starter with the reactive Netty server:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-webflux</artifactId>
</dependency>This starter replaces Tomcat and spring-boot-starter-web — the application runs on Netty with a non-blocking event-loop model.
A WebFlux controller returns Mono and Flux, not plain objects:
@RestController
@RequestMapping("/api/items")
public class ItemController {
private final ItemService service;
public ItemController(ItemService service) {
this.service = service;
}
@GetMapping
public Flux<Item> listItems() {
return service.findAll();
}
@GetMapping("/{id}")
public Mono<ResponseEntity<Item>> getItem(@PathVariable Long id) {
return service.findById(id)
.map(ResponseEntity::ok)
.defaultIfEmpty(ResponseEntity.notFound().build());
}
}No thread is waiting. When the data is ready, the response is sent; while it isn't, the thread is used for other requests. Note the use of defaultIfEmpty to handle data that isn't found.
Reactor's power lies in operators that can be chained. An example combining two data sources:
Mono<Item> item = service.findById(1L);
Mono<Supplier> supplier = supplierService.findById(1L);
Mono<ItemDetail> detail = Mono.zip(item, supplier)
.map(tuple -> new ItemDetail(tuple.getT1(), tuple.getT2()));Mono.zip combines the results of two publishers into one — both run in parallel without blocking threads. Operator chains like map, flatMap, and zip build elegant data pipelines. From the client side, reactive endpoints are still tested the usual way: curl http://localhost:8080/api/items.
R2DBC enables reactive database access. Add the dependencies:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-r2dbc</artifactId>
</dependency>
<dependency>
<groupId>io.r2dbc</groupId>
<artifactId>r2dbc-postgresql</artifactId>
</dependency>Configure the R2DBC connection:
spring:
r2dbc:
url: r2dbc:postgresql://localhost:5432/belajar
username: belajar
password: rahasiaReactive repositories work hand in hand with Mono and Flux:
public interface ItemRepository
extends ReactiveCrudRepository<Item, Long> {
Flux<Item> findByNameContaining(String keyword);
}All methods — save, findAll, findById — return publishers, so nothing blocks when communicating with the database. The entire pipeline from HTTP request to database query becomes non-blocking.
Here's a comparison you should understand:
Reactive is not a universal replacement. Blocking logic — such as blocking JDBC calls — cancels out the benefits of reactivity. WebFlux shines most in applications dominated by asynchronous I/O operations that need to scale to a large number of connections.
High traffic, I/O intensive -> WebFlux
Standard business apps -> Spring MVCEpisode 15 equipped you with reactive programming: understanding Mono, Flux, and backpressure, building non-blocking applications with Spring WebFlux, integrating the reactive R2DBC database, and evaluating when the reactive paradigm beats servlet-based.
Key takeaways:
Mono emits one value; Flux emits many values as a stream.Mono and Flux, not plain objects.In the next episode, episode 16, we'll discuss performance and JVM optimizations — profiling with JFR and async-profiler, tuning the heap and JVM flags with the G1 and ZGC collectors, optimizing startup time and memory footprint, and tuning cache and connection pools.