Implementing Reactive Programming
1. Implementing Reactive Streams
| Interface | Role |
| Publisher | Emits items |
| Subscriber | Receives items |
| Subscription | Controls demand (request/cancel) |
| Processor | Both publisher and subscriber |
2. Using Mono and Flux
Example: Project Reactor
Mono<User> one = userRepo.findById(id); // 0..1
Flux<Order> many = orderRepo.findByUser(id); // 0..N
Flux.range(1, 5)
.map(i -> i * 2)
.filter(i -> i > 4)
.subscribe(System.out::println);
3. Implementing Reactive Operators
| Operator | Use |
| map | Transform 1:1 |
| flatMap | Transform with async result |
| filter | Keep matching |
| zip | Combine N streams item-wise |
| merge / concat | Combine sequentially / concurrently |
| switchIfEmpty | Default when empty |
| retryWhen | Conditional retry |
4. Handling Backpressure
| Strategy | Detail |
| BUFFER | Queue items (memory risk) |
| DROP | Discard newest |
| LATEST | Keep only most recent |
| ERROR | Signal overflow |
| request(n) | Pull-based control |
5. Implementing Reactive Repositories
Example: R2DBC repository
public interface OrderRepository extends ReactiveCrudRepository<Order, UUID> {
Flux<Order> findByCustomerId(UUID customerId);
Mono<Long> countByStatus(String status);
}
6. Implementing Reactive Web Controllers
Example: WebFlux
@RestController @RequestMapping("/orders")
public class OrderController {
@GetMapping("/{id}")
public Mono<Order> get(@PathVariable UUID id) { return service.findById(id); }
@GetMapping(produces = MediaType.TEXT_EVENT_STREAM_VALUE)
public Flux<Order> stream() { return service.streamAll(); }
}
7. Handling Reactive Error Handling
| Operator | Use |
| onErrorReturn | Default value on error |
| onErrorResume | Switch to alternate publisher |
| onErrorMap | Translate exception |
| retry / retryWhen | Retry on error |
| doOnError | Side effect (logging) |
8. Implementing Reactive Composition
Example: Combine sources
Mono<OrderDetails> details = Mono.zip(
orderService.findById(id),
customerService.findByOrderId(id),
shippingService.estimate(id))
.map(t -> new OrderDetails(t.getT1(), t.getT2(), t.getT3()));
9. Implementing Reactive Testing
Example: StepVerifier
StepVerifier.create(service.findById(id))
.expectNextMatches(o -> o.id().equals(id))
.verifyComplete();
StepVerifier.create(failing)
.expectError(NotFoundException.class)
.verify();
10. Handling Schedulers
| Scheduler | Use |
| Schedulers.parallel() | CPU-bound; size = cores |
| Schedulers.boundedElastic() | Blocking I/O |
| Schedulers.single() | Single thread |
| subscribeOn | Where source runs |
| publishOn | Where downstream runs |
11. Implementing Reactive Caching
| Operator | Use |
| cache() | Replay all values to late subscribers |
| cache(Duration) | TTL-based |
| CacheMono | External-cache-backed |
12. Implementing Reactive Security
| Concern | Detail |
| SecurityWebFilterChain | WebFlux equivalent of HttpSecurity |
| ReactiveSecurityContextHolder | Context propagated via reactor context |
| @PreAuthorize | Returns Mono/Flux; checks before subscribe |
Note: Java 21 virtual threads NEW often beat reactive for typical web apps with simpler code.