概述

  • 传统的基于 Servlet 的 Web 框架,如 Spring MVC,在本质上都是阻塞和多线程的,每个连接都会使用一个线程。在请求处理的时候,会在线程池中拉取一个工作者( worker )线程来对请求进行处理。同时,请求线程是阻塞的,直到工作者线程提示它已经完成为止。

  • Spring WebFlux 是异步、非阻塞的 WEB 模块,支持 Reactive Streams 背压,并在 Netty、Undertow 和 Servlet 容器等服务器上运行。

  • 通常它们只需要与 CPU 核⼼数量相同的线程。通过使⽤所谓的事件轮询(event looping)机制,这些框架能够⽤⼀个线程处理很多请求,这样每次连接的成本会更低。在事件轮询中,所有事情都是以事件的⽅式来进⾏处理的,包括请求以及密集型操作(如数据库和⽹络操作)的回调。当需要执⾏成本⾼昂的操作时,事件轮询会为该操作注册⼀个回调,这样操作可以并⾏执⾏,⽽事件轮询则会继续处理其他的事件
    20250806203942

20250806204041

为什么要创建 Spring WebFlux?

  • 需要一个非阻塞的 Web 栈来处理少量线程的并发,并以较少的硬件资源进行扩展。
  • 函数式编程。Spring WebFlux 能够在注解的 controller 的同时提供函数式的 Web 端点。

Spring MVC 依赖于 Servlet 阻塞式 I/O,并让应用程序在需要时直接使用 Servlet API。Spring WebFlux 依赖于 Servlet 的非阻塞 I/O,并在一个低级别的适配器后面使用 Servlet API。它没有被暴露出来以供直接使用。

响应式

reactive(响应式):指的是围绕对变化做出反应的编程模型—​ 对 I/O 事件做出反应的网络组件,对鼠标事件做出反应的 UI controller


Reactor 是 Spring WebFlux 的首选响应式库。它提供了 Mono 和 Flux API 类型,通过与 ReactiveX 运算符词汇 相一致的丰富运算符集,对 0..1(Mono)和 0..N(Flux)的数据序列进行操作
关于 Reactor 的介绍请移步我关于 Reactor 的相关文档,会有详细的介绍


WebFlux 需要 Reactor 作为核心依赖,但它可以通过 Reactive Streams 与其他响应式库互操作。一般来说,WebFlux API 接受一个普通的 Publisher 作为输入,在内部将其调整为 Reactor 类型,使用该类型,并返回 Flux 或 Mono 作为输出。因此,你可以传递任何 Publisher 作为输入,你可以在输出上应用操作,但你需要调整输出,以便与另一个响应式库一起使用。

编程模型

  1. 注解式 COntroller:与 Spring MVC 一致,基于 spring-web 模块的相同注解。Spring MVC 和 WebFlux Controller 都支持响应式(Reactor 和 RxJava)返回类型,因此,要区分它们并不容易。
  2. 函数式端点:基于 Lambda 的、轻量级的、函数式的编程模型。你可以把它看成是一个小型的库或一组实用程序,应用程序可以用它来路由和处理请求。和注解式 controller 的最大区别是,应用程序从头到尾负责处理请求,而不是通过注解声明意图并被回调。

核心

HttpHandler

HttpHandler 是一个简单的契约,有一个处理请求和响应的单一方法。 用于 HTTP 请求处理的基本约定,具有非阻塞 I/O 和 Reactive Streams 背压,以及 Reactor Netty、Undertow、Tomcat、Jetty 和任何 Servlet 容器的适配器。

WebHandler API

WebHandler API 的目标是提供一套更广泛的在 Web 应用程序中常用的功能,用于处理请求的通用 web API,在此基础上建立具体的编程模型,如注解 controller 和函数式端点。

过滤器

在 WebHandler API, 中,你可以使用 WebFilter 在过滤器和目标 WebHandler 的其他处理链之前和之后应用拦截式逻辑

DispatcherHandler

与 Spring MVC 类似,Spring WebFlux 也是围绕 front controller 模式设计的,其中一个中央 WebHandler,即 DispatcherHandler,为请求处理提供一个共享算法,而实际工作则由可配置的委托组件执行。


DispatcherHandler 从 Spring 配置中发现了它所需要的委托组件。它也被设计成 Spring Bean 本身,并实现了 ApplicationContextAware 以访问它所运行的 context。
实现:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// org.springframework.web.reactive.DispatcherHandler#handle
@Override
public Mono<Void> handle(ServerWebExchange exchange) { // exchange中放着http请求响应信息
if (this.handlerMappings == null) { // 根据请求地址获取对应的mapping
return createNotFoundError();
}
if (CorsUtils.isPreFlightRequest(exchange.getRequest())) {
return handlePreFlight(exchange);
}
return Flux.fromIterable(this.handlerMappings)
.concatMap(mapping -> mapping.getHandler(exchange))
.next()
.switchIfEmpty(createNotFoundError())
.flatMap(handler -> invokeHandler(exchange, handler)) // 调用业务方法
.flatMap(result -> handleResult(exchange, result)); // 处理结果返回
}