Spring Boot + WebFlux 全面使用实践指南

 更新时间:2026年01月19日 10:45:20   作者:谁在黄金彼岸  
SpringWebFlux是Spring Framework 5+提供的响应式Web框架,性能与配置优化包括调整Netty参数、启用背压控制和监控指标,常见陷阱与最佳实践,本文给大家介绍Spring Boot+WebFlux全面使用指南,感兴趣的朋友跟随小编一起看看吧

一、什么是 Spring WebFlux?

  • 定位:Spring Framework 5+ 提供的 响应式 Web 框架,与 Spring MVC 并列;
  • 核心目标:支持 非阻塞、异步、事件驱动 的高并发 Web 应用;
  • 底层依赖
    • 响应式流规范(Reactive Streams)
    • Project Reactor(Mono / Flux
    • 非阻塞服务器(默认 Netty,也支持 Undertow、Servlet 3.1+ 容器)

✅ WebFlux ≠ WebMVC 替代品,而是 互补技术栈,适用于不同场景。

二、何时使用 WebFlux?

场景推荐
高并发 I/O 密集型(API 网关、实时推送、IoT)✅ 强烈推荐
全链路响应式技术栈(R2DBC + WebClient + Reactive MQ)
低并发传统业务系统(后台管理、简单 CRUD)❌ 用 WebMVC 更简单
强事务性/复杂 SQL(需 Hibernate/JPA)❌ 不适合

三、快速入门:创建 WebFlux 项目

1. 使用 Spring Initializr(https://start.spring.io/)

选择:

  • Project: Maven / Gradle
  • Language: Java
  • Spring Boot: 3.x(推荐)
  • Dependencies:
    • Spring Reactive Web
    • Spring Data R2DBC(如需数据库)
    • H2 DatabaseMariaDB Driver(根据需要)

2. 手动添加依赖(Maven)

<dependencies>
    <!-- WebFlux 核心 -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-webflux</artifactId>
    </dependency>
    <!-- 响应式数据库(以 MariaDB 为例) -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-data-r2dbc</artifactId>
    </dependency>
    <dependency>
        <groupId>org.mariadb</groupId>
        <artifactId>r2dbc-mariadb</artifactId>
        <version>1.1.5</version>
    </dependency>
    <dependency>
        <groupId>org.mariadb</groupId>
        <artifactId>mariadb-java-client</artifactId>
        <scope>runtime</scope>
    </dependency>
    <!-- 测试 -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-test</artifactId>
        <scope>test</scope>
    </dependency>
    <dependency>
        <groupId>io.projectreactor</groupId>
        <artifactId>reactor-test</artifactId>
        <scope>test</scope>
    </dependency>
</dependencies>

3. 启动类(无需特殊注解)

@SpringBootApplication
public class WebfluxDemoApplication {
    public static void main(String[] args) {
        SpringApplication.run(WebfluxDemoApplication.class, args);
    }
}

🔍 启动日志将显示:Netty started on port 8080

四、两种编程模型

A. 注解式(Annotation-based)— 类似 Spring MVC

@RestController
@RequestMapping("/users")
public class UserController {
    @Autowired
    private UserRepository userRepository;
    // 返回单个对象
    @GetMapping("/{id}")
    public Mono<User> getUser(@PathVariable String id) {
        return userRepository.findById(id);
    }
    // 返回列表流
    @GetMapping
    public Flux<User> getAllUsers() {
        return userRepository.findAll();
    }
    // 创建用户
    @PostMapping
    public Mono<User> createUser(@RequestBody User user) {
        return userRepository.save(user);
    }
    // SSE:服务器推送事件
    @GetMapping(value = "/stream", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
    public Flux<String> streamEvents() {
        return Flux.interval(Duration.ofSeconds(1))
                   .map(seq -> "Event #" + seq);
    }
}

✅ 优点:学习成本低,与 MVC 风格一致
⚠️ 注意:方法必须返回 MonoFlux

B. 函数式(Functional)— 纯函数式路由

1. 定义 Handler

@Component
public class UserHandler {
    private final UserRepository userRepository;
    public UserHandler(UserRepository userRepository) {
        this.userRepository = userRepository;
    }
    public Mono<ServerResponse> getUser(ServerRequest request) {
        String id = request.pathVariable("id");
        Mono<User> user = userRepository.findById(id);
        return user
            .flatMap(u -> ServerResponse.ok().bodyValue(u))
            .switchIfEmpty(ServerResponse.notFound().build());
    }
    public Mono<ServerResponse> getAllUsers(ServerRequest request) {
        Flux<User> users = userRepository.findAll();
        return ServerResponse.ok().body(users, User.class);
    }
}

2. 定义 RouterFunction(替代 @RequestMapping)

@Configuration
public class UserRouter {
    @Bean
    public RouterFunction<ServerResponse> userRoutes(UserHandler handler) {
        return route()
            .GET("/users/{id}", handler::getUser)
            .GET("/users", handler::getAllUsers)
            .build();
    }
}

✅ 优点:更符合响应式思想,易于单元测试,无反射开销
💡 适合构建轻量级、高内聚的 API

五、响应式数据访问(R2DBC)

1. 实体类

@Table("users")
public class User {
    @Id
    private Long id;
    private String name;
    private String email;
    // constructors, getters, setters
}

2. Repository

public interface UserRepository extends ReactiveCrudRepository<User, Long> {
    Flux<User> findByEmail(String email);
}

3. application.yml 配置

spring:
  r2dbc:
    url: r2dbc:mariadb://localhost:3306/mydb
    username: root
    password: password

支持连接池(需引入 io.r2dbc:r2dbc-pool

六、响应式 HTTP 客户端:WebClient

替代 RestTemplate,非阻塞调用外部服务:

@Service
public class ExternalServiceClient {
    private final WebClient webClient;
    public ExternalServiceClient() {
        this.webClient = WebClient.builder()
            .baseUrl("https://api.example.com")
            .build();
    }
    public Mono<UserProfile> fetchProfile(String userId) {
        return webClient.get()
            .uri("/profiles/{id}", userId)
            .retrieve()
            .bodyToMono(UserProfile.class)
            .onErrorResume(e -> Mono.empty()); // 错误降级
    }
}

七、全局异常处理

@ControllerAdvice
public class GlobalExceptionHandler {
    @ExceptionHandler(UserNotFoundException.class)
    public Mono<ResponseEntity<String>> handleUserNotFound(Exception ex) {
        return Mono.just(ResponseEntity
            .status(HttpStatus.NOT_FOUND)
            .body("User not found"));
    }
    @ExceptionHandler(Exception.class)
    public Mono<ResponseEntity<String>> handleGeneral(Exception ex) {
        return Mono.just(ResponseEntity
            .status(HttpStatus.INTERNAL_SERVER_ERROR)
            .body("Internal error"));
    }
}

也可使用函数式方式注册 WebExceptionHandler

八、测试:WebTestClient

@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
class UserControllerTest {
    @Autowired
    private WebTestClient webClient;
    @Test
    void shouldGetUser() {
        webClient.get().uri("/users/1")
            .exchange()
            .expectStatus().isOk()
            .expectBody(User.class)
            .value(user -> assertThat(user.getName()).isEqualTo("Alice"));
    }
}

九、性能与配置优化

1. 调整 Netty 参数(application.yml)

server:
  netty:
    connection-timeout: 30s
    max-in-memory-size: 10MB  # 防止 OOM

2. 启用背压控制

Flux.range(1, 1000)
    .limitRate(100) // 控制上游发射速率
    .onBackpressureBuffer(500); // 缓冲溢出数据

3. 监控与指标

集成 Micrometer + Prometheus,监控 reactor.netty.connection.provider.active.connections 等指标。

十、常见陷阱与最佳实践

问题建议
在 WebFlux 中调用 JDBC / Thread.sleep()❌ 会阻塞 EventLoop,导致服务不可用
混合使用 WebMVC 和 WebFlux⚠️ 可以共存,但不要在同一个 Controller 中混用
忽略背压⚠️ 大流量下可能 OOM,务必使用 limitRate / onBackpressureXXX
过度使用 block()❌ 破坏响应式模型,仅用于测试或边界转换

✅ 总结:WebFlux 开发 Checklist

  • 使用 spring-boot-starter-webflux
  • 返回类型为 Mono<T>Flux<T>
  • 数据库使用 R2DBC(非 JDBC)
  • HTTP 调用使用 WebClient
  • 避免任何阻塞操作
  • 使用 WebTestClient 测试
  • 合理处理背压和错误

通过以上指南,你已掌握 Spring Boot + WebFlux 的完整开发能力。记住:WebFlux 的价值不在于“更快”,而在于“更高吞吐、更低资源消耗”。在合适的场景下使用它,将显著提升系统伸缩性。

官方文档:

到此这篇关于Spring Boot + WebFlux 全面使用实践指南的文章就介绍到这了,更多相关Spring Boot WebFlux使用内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • SpringBoot3使用RestTemplate请求接口忽略SSL证书的问题解决

    SpringBoot3使用RestTemplate请求接口忽略SSL证书的问题解决

    本文主要介绍了SpringBoot3使用RestTemplate请求接口忽略SSL证书的问题解决,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2025-10-10
  • 一文了解Java中枚举的使用

    一文了解Java中枚举的使用

    Java中枚举,大家在项目中经常使用吧,主要用来定义一些固定值。那你了解枚举的本质吗?了解枚举的一些常见用法吗?本文就来为大家一一进行详解
    2022-09-09
  • java跳出循环的三种方式总结(break语句、continue语句和return语句)

    java跳出循环的三种方式总结(break语句、continue语句和return语句)

    在实际编程中,有时需要在条件语句匹配的时候跳出循环,下面这篇文章主要给大家介绍了关于java跳出循环的三种方式,其中包括break语句、continue语句和return语句的相关资料,需要的朋友可以参考下
    2023-03-03
  • 使用SkyWalking监控Java服务的过程

    使用SkyWalking监控Java服务的过程

    这篇文章主要介绍了使用SkyWalking监控Java服务,介绍一个对源码0入侵的Java服务监控方式,SkyWalking Agent,只需要启动Java程序的时候加几个参数,就能对Java服务进行可视化监控,需要的朋友可以参考下
    2023-08-08
  • Java案例使用比较排序器comparator实现成绩排序

    Java案例使用比较排序器comparator实现成绩排序

    这篇文章主要介绍了Java案例使用比较排序器comparator实现成绩排序,主要通过案例用TreeSet集合存储多个学生信息,并遍历该集合,要按照总分从高到低进行排序,下文介绍需要的朋友可以参考一下
    2022-04-04
  • java中jvm逃逸问题分析

    java中jvm逃逸问题分析

    本篇文章给大家详细总结了java中jvm逃逸问题的相关内容,有兴趣的朋友可以根据小编一起学习下。
    2018-02-02
  • java中split()方法以及常见算法经典案例

    java中split()方法以及常见算法经典案例

    这篇文章主要介绍了java中split()方法以及常见算法的相关资料,split()方法可以根据指定的正则表达式将字符串分割成多个子字符串,并返回一个字符串数组,文中通过代码介绍的非常详细,需要的朋友可以参考下
    2025-04-04
  • javaWeb实现简单文件上传

    javaWeb实现简单文件上传

    这篇文章主要为大家详细介绍了JAVAWeb实现简单文件上传,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2022-06-06
  • sprng和struts有什么区别?

    sprng和struts有什么区别?

    Spring和Struts都是近年来比较流行的框架,Struts主要用于表示层,Spring用于业务层,以及Hiberate主要用于持久层,
    2015-06-06
  • Java常见的阻塞队列总结

    Java常见的阻塞队列总结

    今天我们来讨论另外一类容器:阻塞队列,文中有非常详细的代码示例及介绍,对正在学习JAVA的小伙伴们很有帮助,需要的朋友可以参考下
    2021-06-06

最新评论