Building Reactive Applications with WebFlux
1. Adding Spring WebFlux Dependencies
Example: WebFlux dependency
< dependency >
< groupId >org.springframework.boot</ groupId >
< artifactId >spring-boot-starter-webflux</ artifactId >
</ dependency >
Warning: Don't include spring-boot-starter-web together — Boot
picks the wrong server type.
2. Understanding Reactive Streams
Component
Role
Publisher<T>
Emits items asynchronously
Subscriber<T>
Consumes items + signals
Subscription
Backpressure control: request(n), cancel()
Processor
Both publisher + subscriber
3. Using Mono for Single Values
Example: Mono: map and default value
Mono< User > user = userRepo. findById (id);
Mono< String > name = user. map (User :: getName). defaultIfEmpty ( "anonymous" );
Mono. empty (); Mono. just (x); Mono. error (ex);
4. Using Flux for Multiple Values
Example: Flux: filter and limit stream
Flux< Order > recent = orderRepo. findByCreatedAfter (Instant. now (). minus ( 1 , HOURS))
. filter (o -> o. total (). compareTo (BigDecimal.TEN) > 0 )
. take ( 100 );
5. Creating Reactive REST Controllers
Example: Reactive CRUD controller
@ RestController
@ RequestMapping ( "/api/users" )
public class UserApi {
private final UserRepo repo;
public UserApi (UserRepo repo ) { this .repo = repo; }
@ GetMapping public Flux< User > all () { return repo. findAll (); }
@ GetMapping ( "/{id}" ) public Mono<ResponseEntity< User >> one (@ PathVariable Long id ) {
return repo. findById (id). map (ResponseEntity :: ok). defaultIfEmpty (ResponseEntity. notFound (). build ());
}
@ PostMapping public Mono< User > create (@ RequestBody Mono< User > body ) {
return body. flatMap (repo :: save);
}
}
6. Implementing Reactive Repositories
Interface
For
ReactiveCrudRepository
Generic reactive CRUD
ReactiveSortingRepository
+ Sort
R2dbcRepository
R2DBC SQL DBs
ReactiveMongoRepository
MongoDB
ReactiveRedisRepository
Redis
7. Using Reactive Database Drivers (R2DBC)
Example: R2DBC datasource configuration
spring :
r2dbc :
url : r2dbc:postgresql://localhost/app
username : app
password : ${DB_PASS}
8. Handling Backpressure Strategies
Operator
Strategy
onBackpressureBuffer()
Buffer overflow
onBackpressureDrop()
Drop excess items
onBackpressureLatest()
Keep latest only
onBackpressureError()
Signal error
limitRate(n)
Cap upstream demand
9. Implementing Server-Sent Events
Example: Server-sent events stream with Flux
@ GetMapping ( value = "/events" , produces = MediaType.TEXT_EVENT_STREAM_VALUE)
public Flux < ServerSentEvent < Quote >> quotes () {
return Flux. interval (Duration. ofSeconds ( 1 ))
. map (i -> ServerSentEvent. < Quote > builder ()
. id (String. valueOf (i)). event ( "quote" ). data (quoteService. next ()). build ());
}
10. Testing Reactive Endpoints (WebTestClient)
Example: Test reactive endpoint with WebTestClient
@ WebFluxTest (UserApi.class)
class UserApiTests {
@ Autowired WebTestClient client;
@ MockBean UserRepo repo;
@ Test void list () {
when (repo. findAll ()). thenReturn (Flux. just ( new User ( 1L , "a" )));
client. get (). uri ( "/api/users" ). exchange ()
. expectStatus (). isOk (). expectBodyList (User.class). hasSize ( 1 );
}
}
11. Using Reactive Operators
Operator
Purpose
map / flatMap
Transform / chain async
filter
Predicate
zip / merge / concat
Combine
switchIfEmpty / defaultIfEmpty
Empty fallback
retry / retryWhen
Re-subscribe on error
timeout(d)
Error if no signal
publishOn / subscribeOn
Switch scheduler
cache()
Replay to late subscribers