Skip to main content
Advertisement

13.1 Overview of Spring WebFlux and Comparison with MVC

Introduced in Spring 5.0, Spring WebFlux is an asynchronous, non-blocking reactive web framework. This section explores how it differs from traditional Spring MVC and why it is necessary.

1. Background of WebFlux

Standard Spring MVC (Servlet-based) uses a Thread-per-Request model, where each request is assigned its own thread. This approach has limitations: as concurrent users increase, the thread count rises, leading to high memory consumption and significant context-switching overhead.

WebFlux was created to handle massive numbers of concurrent connections efficiently using a small number of threads.

Core Concept: Reactive Programming

Reactive programming is a programming paradigm focused on data streams and the propagation of change. It operates by pushing data to consumers whenever it is produced, with asynchronous processing as a default.

2. Key Comparison: Spring MVC vs. Spring WebFlux

FeatureSpring MVCSpring WebFlux
ModelSynchronous + BlockingAsynchronous + Non-blocking
ProcessingThread-per-requestEvent Loop (High concurrency with fewer threads)
StackServlet API (Tomcat, etc.)Reactive Streams (Netty, etc.)
DatabaseJDBC (Blocking)R2DBC, NoSQL (Non-blocking)
Recommended UseStandard web apps, typical CRUDStreaming, Chatting, high server-to-server calls (MSA)

3. Reactive Streams (Mono and Flux)

To understand WebFlux, you must know the two core types provided by the Reactor library:

Project Reactor and Publisher-Subscriber Pattern

Reactor is a library that implements the Reactive Streams standard, defining the relationship between the Publisher(who emits data) and the ** Subscriber**(who consumes it).

  1. Subscribe: The Subscriber subscribes to the Publisher.
  2. Request: The Subscriber requests a specific number of data items from the Publisher (** Backpressure**).
  3. onNext: The Publisher delivers the data.
  4. onComplete / onError: The process finishes when all data is delivered or an error occurs.

Core Data Types: Mono and Flux

  • Mono<T>: Emits 0 or 1 item (Single response).
  • Flux<T>: Emits 0 to N items (Multiple responses, streaming).
// Mono Example: Emits "HONG" upon success and then completes
Mono<String> name = Mono.just("Hong")
.map(String::toUpperCase)
.flatMap(s -> Mono.just("Name: " + s));

// Flux Example: Useful for multiple items (Use instead of List)
Flux<Integer> numbers = Flux.just(1, 2, 3, 4, 5)
.filter(n -> n % 2 == 0)
.map(n -> n * 10);

4. Controller Implementation Styles

WebFlux supports both the traditional @Controller approach (Annotated Controller) and a newer functional model (Functional Endpoints).

1) Annotated Controller

Familiar to MVC users, but returning types must be Mono or Flux.

@RestController
public class HelloController {
@GetMapping("/hello")
public Mono<String> hello() {
return Mono.just("Hello, WebFlux!");
}
}

2) Functional Endpoints

Separates Routing and Handling logic for more declarative endpoint definitions.

@Component
public class HelloHandler {
public Mono<ServerResponse> hello(ServerRequest request) {
return ServerResponse.ok().bodyValue("Hello, Reactive!");
}
}

@Configuration
public class HelloRouter {
@Bean
public RouterFunction<ServerResponse> route(HelloHandler handler) {
return RouterFunctions.route(RequestPredicates.GET("/hello"), handler::hello);
}
}

5. Practical Considerations

  • Non-blocking Chain: Including blocking code (e.g., standard JDBC, Thread.sleep) in a WebFlux environment will drastically degrade performance. Every library in the chain must support non-blocking.
  • Multi Event Loop: WebFlux uses a multi-event loop model to process thousands of requests with a small number of fixed threads (usually CPU cores * 2). Be careful not to let a specific request occupy a thread for too long.
  • Backpressure Management: It includes mechanisms to control load when the consumer's speed is slower than the producer's, enhancing system stability.
  • Learning Curve: Reactive programming requires a shift in mindset compared to imperative programming and can be harder to debug.
Advertisement