Springboot 3.x - Reactive programming (2)

This article mainly introduces the difference between Webflux and traditional MVC web,and how to integrate it into springboot3.x or 2.x.

一、WebFlux vs WebMVC

Blocking Web (Servlet) and Reactive Web (WebFlux) are two paradigms in Spring Web development, each with distinct characteristics and design principles. Here, we will expand on the differences between them, focusing on various aspects of their implementation and usage.

1. Front Controller

Servlet-Blocking Web: Uses DispatcherServlet as the front controller. The DispatcherServlet is responsible for handling all incoming HTTP requests and routing them to appropriate handler methods within the application.

WebFlux-Reactive Web: Uses DispatcherHandler as the front controller. Similar to DispatcherServlet, the DispatcherHandler manages HTTP request routing but is designed to work in a non-blocking, reactive manner, leveraging the reactive streams API.

2. Handler

Servlet-Blocking Web: Uses Controller as the handler. These controllers are typically annotated with @Controller or @RestController and contain methods mapped to specific HTTP routes, handling synchronous request-response cycles.

WebFlux-Reactive Web: Uses WebHandler or Controller as the handler. WebHandler is a functional interface representing a contract for handling web requests reactively. Controllers can also be used, but they must return reactive types like Mono or Flux.

3. Request and Response

Servlet-Blocking Web: Uses ServletRequest and ServletResponse. These are standard Java EE interfaces representing the request and response objects in a traditional, blocking I/O model.

WebFlux-Reactive Web: Uses ServerWebExchange, along with ServerRequest and ServerResponse. ServerWebExchange is a central interface in WebFlux that provides access to the HTTP request and response, enabling non-blocking processing.

4. Filters

Servlet-Blocking Web: Uses Filter (e.g., HttpFilter). Filters are used to perform filtering tasks on either the request to a resource, the response from a resource, or both. They operate in a blocking manner.

WebFlux-Reactive Web: Uses WebFilter. Similar to Servlet filters, WebFilter allows for request and response modification but in a non-blocking, reactive way.

5. Exception Handlers

Servlet-Blocking Web: Uses HandlerExceptionResolver to handle exceptions. This interface allows the application to define custom exception handling logic for synchronous requests.

WebFlux-Reactive Web: Uses DispatchExceptionHandler to handle exceptions. This handler is designed for reactive applications and can process exceptions in a non-blocking manner.

6. Web Configuration

Servlet-Blocking Web: Configured via @EnableWebMvc. This annotation is used to enable Spring MVC and import its default configuration, tailored for blocking, synchronous request processing.

WebFlux-Reactive Web: Configured via @EnableWebFlux. This annotation enables WebFlux and imports its configuration, optimized for reactive, non-blocking request handling.

7. Custom Configuration

Servlet-Blocking Web: Uses WebMvcConfigurer. This interface allows customization of the default Spring MVC configuration, such as view resolvers, interceptors, and formatters.

WebFlux-Reactive Web: Uses WebFluxConfigurer. Similar to WebMvcConfigurer, this interface provides hooks for customizing WebFlux's configuration.

8. Return Types

Servlet-Blocking Web: The return type can be any object. Methods in controllers can return simple objects, ModelAndView, ResponseEntity, or any other type, which are then processed synchronously.

WebFlux-Reactive Web: The return type can be a Mono, a Flux, or any object. Methods in reactive controllers often return Mono (representing a single asynchronous value) or Flux (representing a stream of asynchronous values), facilitating non-blocking operations.

9. Sending REST Requests

Servlet-Blocking Web: Uses RestTemplate to send REST requests. RestTemplate is a synchronous client to perform HTTP requests and interact with RESTful web services.

WebFlux-Reactive Web: Uses WebClient to send REST requests. WebClient is a non-blocking, reactive alternative to RestTemplate, designed to work seamlessly with reactive programming paradigms.

Core Difference Between Blocking and Reactive Models

Blocking Model (Servlet): Each request is handled by a dedicated thread, which waits for operations to complete (such as database queries or IO operations). This model can lead to thread exhaustion under high concurrency, affecting system performance.

Reactive Model (WebFlux): Uses a non-blocking IO model with a small number of threads handling many requests. It leverages callback mechanisms, event-driven architecture, and asynchronous non-blocking IO for efficient resource utilization and high concurrency handling. Key features of the reactive programming model include:

  • Non-blocking Operations: Operations do not block the current thread, allowing it to continue processing other tasks.
  • Callback Mechanism: Handles subsequent steps through callback mechanisms once an operation completes.
  • Event-driven Architecture: Processes requests based on an event-driven approach.

This model is more efficient in resource usage and is suitable for scenarios requiring high concurrency and large traffic volumes.

Summary

The choice between a blocking or reactive web framework depends on specific application scenarios and requirements. If the application is primarily I/O-intensive with high concurrency needs, then WebFlux is a more suitable choice; if it involves CPU-intensive tasks, the traditional Servlet model might be more appropriate.

二、Integration with Springboot

Spring WebFlux is the new reactive web framework introduced in Spring Framework 5.0. Unlike Spring MVC, it does not require the servlet API, is fully asynchronous and non-blocking, and implements the Reactive Streams specification through the Reactor project.

Spring WebFlux comes in two flavors: functional and annotation-based. The annotation-based one is quite close to the Spring MVC model, as shown in the following example:

java 复制代码
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;

import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

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

    private final UserRepository userRepository;

    private final CustomerRepository customerRepository;

    public MyRestController(UserRepository userRepository, CustomerRepository customerRepository) {
        this.userRepository = userRepository;
        this.customerRepository = customerRepository;
    }

    @GetMapping("/{userId}")
    public Mono<User> getUser(@PathVariable Long userId) {
        return this.userRepository.findById(userId);
    }

    @GetMapping("/{userId}/customers")
    public Flux<Customer> getUserCustomers(@PathVariable Long userId) {
        return this.userRepository.findById(userId).flatMapMany(this.customerRepository::findByUser);
    }

    @DeleteMapping("/{userId}")
    public Mono<Void> deleteUser(@PathVariable Long userId) {
        return this.userRepository.deleteById(userId);
    }

}

"WebFlux.fn", the functional variant, separates the routing configuration from the actual handling of the requests, as shown in the following example:

java 复制代码
import org.springframework.boot.SpringBootConfiguration;
import org.springframework.context.annotation.Bean;
import org.springframework.http.MediaType;
import org.springframework.web.reactive.function.server.RequestPredicate;
import org.springframework.web.reactive.function.server.RouterFunction;
import org.springframework.web.reactive.function.server.ServerResponse;

import static org.springframework.web.reactive.function.server.RequestPredicates.accept;
import static org.springframework.web.reactive.function.server.RouterFunctions.route;

/**
 * <B>Main class name:</B>MyRoutingConfiguration<BR>
 * <B>Summary description:</B>WebFlux router configuration class<BR>
 * @author Chris.Gou
 * @since 2024/07/19 14:53:40
 */
@SpringBootConfiguration(proxyBeanMethods = false)
public class MyRoutingConfiguration {

    /**
     * RequestPredicate is an interface that defines a request predicate, that is, a condition for testing HTTP requests. <BR/>
     * Here, ACCEPT_JSON defines a predicate that checks whether the Accept header of the request is application/json.
     */
    private static final RequestPredicate ACCEPT_JSON = accept(MediaType.APPLICATION_JSON);

    /**
     * RouterFunction<ServerResponse> is an interface that represents a routing function that routes a request to a handler and returns a ServerResponse.
     * @param userHandler
     * @return
     */
    @Bean
    public RouterFunction<ServerResponse> monoRouterFunction(MyUserHandler userHandler) {
        return route() // route() is a static method that returns a RouterFunctions.Builder for building routing functions.
                .GET("/{user}", ACCEPT_JSON, userHandler::getUser)
                .GET("/{user}/customers", ACCEPT_JSON, userHandler::getUserCustomers)
                .DELETE("/{user}", ACCEPT_JSON, userHandler::deleteUser)
                .build();
    }

}
java 复制代码
import org.springframework.stereotype.Component;
import org.springframework.web.reactive.function.server.ServerRequest;
import org.springframework.web.reactive.function.server.ServerResponse;
import reactor.core.publisher.Mono;

/**
 * <B>Main class name:</B>MyUserHandler<BR>
 * <B>Summary description:</B>MyUserHandler<BR>
 * @author Chris.Gou
 * @since 2024/07/19 15:02:47
 */
@Component
public class MyUserHandler {

    public Mono<ServerResponse> getUser(ServerRequest request) {
        // Business processing
        return null;
    }

    public Mono<ServerResponse> getUserCustomers(ServerRequest request) {
        // Business processing
        return null;
    }

    public Mono<ServerResponse> deleteUser(ServerRequest request) {
        // Business processing
        return null;
    }
}

These route definitions enable applications to implement specific business logic by routing requests to corresponding handler methods based on different URL patterns and HTTP methods.

相关推荐
YDS8292 小时前
DeepSeek RAG&MCP + Agent智能体项目 —— RAG知识库的搭建和接口实现
java·ai·springboot·agent·rag·deepseek
candyTong3 小时前
Claude Code 的 Edit 工具是怎么工作的
javascript·后端·架构
未若君雅裁3 小时前
MyBatis 一级缓存、二级缓存与清理机制
java·缓存·mybatis
AI人工智能+电脑小能手4 小时前
【大白话说Java面试题 第65题】【JVM篇】第25题:谈谈对 OOM 的认识
java·开发语言·jvm
GetcharZp4 小时前
GitHub 2.4 万 Star!D2 正在重新定义程序员画图方式
后端
阿维的博客日记4 小时前
Nacos 为什么能让配置动态生效?(涉及 @RefreshScope 注解)
java·spring
雨辰AI4 小时前
SpringBoot3 + 人大金仓读写分离 + 分库分表 + 集群高可用 全栈实战
java·数据库·mysql·政务
辰海Coding5 小时前
MiniSpring框架学习-完成的 IoC 容器
java·spring boot·学习·架构
小小编程路5 小时前
C++ 多线程与并发
java·jvm·c++
AI视觉网奇6 小时前
linux 检索库 判断库是否支持
java·linux·服务器