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使用内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • Spring Boot 中 @Scheduled 定时任务不生效的原因及解决方法

    Spring Boot 中 @Scheduled 定时任务不生效的原因及解决方法

    SpringBoot中@Scheduled注解用于创建定时任务,但有时任务可能不生效,本文介绍Spring Boot 中 @Scheduled 定时任务不生效的原因及解决方法,感兴趣的朋友跟随小编一起看看吧
    2025-11-11
  • Java 面试题和答案 - (下)

    Java 面试题和答案 - (下)

    本文主要介绍Java 面试题,这里整理了Java面试题关于JDBC,线程异常处理,Servlet,JSP的知识的整理,帮助大家理解知识点,便于面试,有兴趣的小伙伴可以参考下
    2016-09-09
  • 从零开始SSM搭建步骤(图文)

    从零开始SSM搭建步骤(图文)

    这篇文章主要介绍了从零开始SSM搭建步骤(图文),文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2021-04-04
  • Java线程编程中isAlive()和join()的使用详解

    Java线程编程中isAlive()和join()的使用详解

    这篇文章主要介绍了Java线程编程中isAlive()和join()的使用详解,是Java入门学习中的基础知识,需要的朋友可以参考下
    2015-09-09
  • JAVA实现图书管理系统项目

    JAVA实现图书管理系统项目

    相信每一个学生学编程的时候,应该都会写一个小项目——图书管理系统。为什么这么说呢?我认为一个学校的氛围很大一部分可以从图书馆的氛围看出来,而图书管理系统这个不大不小的项目,接触的多,也比较熟悉,不会有陌生感,能够练手,又有些难度,所以我的小项目也来了
    2021-10-10
  • 解决StringBuffer和StringBuilder的扩容问题

    解决StringBuffer和StringBuilder的扩容问题

    这篇文章主要介绍了解决StringBuffer和StringBuilder的扩容问题,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2021-07-07
  • Spring IOC简单理解及创建对象的方式

    Spring IOC简单理解及创建对象的方式

    这篇文章主要介绍了Spring IOC简单理解及创建对象的方式,本文通过两种方式给大家介绍创建对象的方法,通过实例代码给大家介绍的非常详细,需要的朋友可以参考下
    2021-09-09
  • Java内存分配多种情况的用法解析

    Java内存分配多种情况的用法解析

    这篇文章主要介绍了Java内存分配多种情况的用法解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2019-11-11
  • 关于SpringBoot整合redis使用Lettuce客户端超时问题

    关于SpringBoot整合redis使用Lettuce客户端超时问题

    使用到Lettuce连接redis,一段时间后不操作,再去操作redis,会报连接超时错误,在其重连后又可使用,纠结是什么原因导致的呢,下面小编给大家带来了SpringBoot整合redis使用Lettuce客户端超时问题及解决方案,一起看看吧
    2021-08-08
  • Java日期类详解(最新推荐)

    Java日期类详解(最新推荐)

    早期版本主要使用 java.util.Date、java.util.Calendar 等类,Java 8及以后引入了新的日期和时间API(JSR 310),包含在java.time包中,本文给大家介绍Java日期类的相关知识,感兴趣的朋友一起看看吧
    2025-06-06

最新评论