Building Reactive Web Apps with Spring WebFlux – part I

Date: 10 June 2023


As web apps grow more complex and interactive, handling large volumes of concurrent users efficiently becomes a critical challenge. Enter Spring WebFlux, Spring’s reactive-stack web framework designed for building non-blocking, event-driven web applications that scale with less hardware.


What Is Reactive Programming?

Reactive programming is a paradigm focused on asynchronous data streams and the propagation of change. Instead of waiting for a task to finish before moving on (blocking), reactive apps work with data as it arrives, allowing better resource utilization and responsiveness.

Spring WebFlux uses Project Reactor under the hood, which implements the Reactive Streams specification with Mono and Flux types.

  • Mono<T>: Represents 0 or 1 element asynchronously.
  • Flux<T>: Represents 0 to many elements asynchronously.

Why Use Spring WebFlux?

  • Efficient handling of many concurrent requests with fewer threads.
  • Ideal for I/O-bound workloads like streaming, chat apps, or reactive APIs.
  • Integrates seamlessly with reactive databases and messaging systems.
  • Supports both annotation-based and functional programming models.

Quick Start: Your First Reactive REST Controller

Step 1: Setup Spring WebFlux

Create a new Spring Boot project with spring-boot-starter-webflux:

spring init -n reactive-demo --dependencies=webflux reactive-demo
cd reactive-demo

Step 2: Create a Reactive REST Controller

@RestController
public class ReactiveController {

    // Return a single async value
    @GetMapping("/mono")
    public Mono<String> getMono() {
        return Mono.just("Hello from Mono!");
    }

    // Return a stream of async values
    @GetMapping(value = "/flux", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
    public Flux<String> getFlux() {
        return Flux.just("Hello", "from", "Flux")
                   .delayElements(Duration.ofSeconds(1));
    }
}
  • The /mono endpoint returns a single value wrapped in a Mono.
  • The /flux endpoint returns a stream of strings (Flux), with a delay to simulate streaming data.

Step 3: Run and Test

./mvnw spring-boot:run

Access http://localhost:8080/mono — you get a simple “Hello from Mono!” response.

Access http://localhost:8080/flux — you’ll see the words “Hello”, “from”, “Flux” emitted one by one every second (thanks to Server-Sent Events).


Reactive Data Access Example

Spring WebFlux pairs perfectly with reactive databases like R2DBC (Reactive Relational Database Connectivity).

Here’s a sample repository for a reactive entity:

@Table("users")
public class User {
    @Id
    private Long id;
    private String name;

    // Getters and setters...
}

public interface UserRepository extends ReactiveCrudRepository<User, Long> {
}

And a reactive service exposing users:

@RestController
@RequestMapping("/users")
public class UserController {

    private final UserRepository userRepository;

    public UserController(UserRepository repo) {
        this.userRepository = repo;
    }

    @GetMapping
    public Flux<User> getAllUsers() {
        return userRepository.findAll();
    }

    @PostMapping
    public Mono<User> createUser(@RequestBody User user) {
        return userRepository.save(user);
    }
}

This leverages reactive streams end-to-end: database, service, and HTTP response.


Error Handling & Backpressure

Spring WebFlux supports powerful error handling and backpressure control, essential for resilient reactive apps:

  • Use onErrorResume or onErrorReturn in your reactive streams.
  • Backpressure automatically signals consumers to slow down data emission.

Example:

@GetMapping("/safe-flux")
public Flux<String> safeFlux() {
    return Flux.just("A", "B", "C")
               .map(value -> {
                   if ("B".equals(value)) throw new RuntimeException("Error!");
                   return value;
               })
               .onErrorResume(e -> Flux.just("Error handled gracefully"));
}

When Not to Use WebFlux

  • CPU-bound, blocking tasks don’t benefit from reactive programming.
  • Legacy libraries or drivers without reactive support can cause blocking calls, negating benefits.
  • For simple CRUD apps with low concurrency, traditional Spring MVC might be simpler.

Conclusion

Spring WebFlux empowers developers to build highly scalable, responsive web applications with the power of reactive programming. While it requires a mindset shift and careful design to avoid blocking calls, the payoff is a modern reactive architecture well-suited for cloud-native, event-driven environments.


Next up: We’ll explore integrating Spring WebFlux with GraphQL and advanced reactive security!


Questions or feedback? Drop a comment below — I’m excited to hear your experiences with reactive programming!

Comments

No comments yet. Why don’t you start the discussion?

Leave a Reply

Your email address will not be published. Required fields are marked *