Spring WebFlux 反应式编程

Mono

// 传统方式
@GetMapping("/user/{id}")
public User getUser(@PathVariable String id) {
    return userService.findUserById(id); // 阻塞直到返回
}

// 响应式方式
@GetMapping("/user/{id}")
public Mono<User> getUser(@PathVariable String id) {
    // 没有立即执行,只是返回了一个描述这个异步操作的 Mono 对象
    // 真正的执行发生在:WebFlux 框架发现 Controller 返回了 Mono,框架自动订阅这个 Mono, 
    // 当 Mono 的值 ready 时,框架把结果写到 HTTP 响应中
    return userService.findUserById(id); // 非阻塞,延迟执行
}

Mono 本身是惰性的,不会自动执行逻辑,只有在被 subscribe() 时才会执行。

客户端最终 "看起来" 是立刻得到了结果,这是因为 WebFlux 在背后处理了整个异步链,并在数据到达时才 "触发" 响应输出。所以虽然服务端是异步非阻塞执行,但是客户端并不知道是用 Mono 还是传统方式,它只是发送 HTTP 请求,然后等响应回来。

Mono 常用方法

创建操作

  • just(T data) - 创建一个包含给定值的 Mono
  • justOrEmpty(@Nullable T data) - 创建可能为空的 Mono
  • fromCallable(Callable<? extends T> supplier) - 从 Callable 创建 Mono
  • fromFuture(CompletableFuture<? extends T> future) - 从 Future 创建 Mono
  • fromRunnable(Runnable runnable) - 从 Runnable 创建 Mono
  • empty() - 创建一个立即完成的空 Mono
  • error(Throwable error) - 创建一个立即错误终止的 Mono
  • never() - 创建一个不发射任何数据的 Mono
  • delay(Duration duration) - 创建一个在延迟后完成的 Mono

转换操作

  • map(Function<? super T, ? extends V> mapper) - 将值转换为其他值
  • flatMap(Function<? super T, ? extends Mono<? extends V>> transformer) - 将值转换为 Mono
  • flatMapMany(Function<? super T, ? extends Publisher<? extends V>> mapper) - 将 Mono 转换为 Flux
  • filter(Predicate<? super T> tester) - 过滤值
  • defaultIfEmpty(T defaultV) - 如果为空则提供默认值
  • switchIfEmpty(Mono<? extends T> alternate) - 如果为空则切换到备用 Mono

组合操作

  • zipWith(Mono<? extends T2> other, BiFunction<? super T, ? super T2, ? extends R> combinator) - 与另一个 Mono 组合
  • then(Mono other) - 完成后执行另一个 Mono
  • thenReturn(V value) - 完成后返回给定值
  • thenMany(Publisher other) - 完成后执行 Flux

错误处理

  • onErrorResume(Function<? super Throwable, ? extends Mono<? extends T>> fallback) - 错误时恢复
  • onErrorReturn(T fallbackValue) - 错误时返回默认值
  • onErrorMap(Function<? super Throwable, ? extends Throwable> mapper) - 转换错误
  • retry() - 重试订阅
  • retryWhen(Function, ? extends Publisher> whenFactory) - 条件重试

其他操作

  • subscribe() - 订阅 Mono
  • subscribe(Consumer<? super T> consumer) - 订阅并处理值
  • block() - 阻塞直到值到达
  • log() - 记录所有信号
  • doOnSuccess(Consumer<? super T> onSuccess) - 成功时的副作用
  • doOnError(Consumer<? super Throwable> onError) - 错误时的副作用
  • doOnSubscribe(Consumer<? super Subscription> onSubscribe) - 订阅时的副作用
  • doOnCancel(Runnable onCancel) - 取消时的副作用

Flux

HTTP SSE (Server-Sent Events) 是一种在 HTTP 单连接下由服务端持续推送数据的机制。

// Spring WebFlux 中 SSE 的实现
@GetMapping(value = "/sse", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
public Flux<String> streamData() {
    // 客户端每隔一秒就收到一次新的数据,可以感知到响应式行为
    return Flux.interval(Duration.ofSeconds(1))
               .map(i -> "当前时间:" + Instant.now());
}

Flux 常用方法

创建操作

  • just(T... data) 创建一个包含给定元素(基础数据、对象、列表等) 的 Flux,元素作为整体一次性返回
  • fromIterable(Iterable<? extends T> it) 从 Iterable 创建 Flux
  • fromArray(T[] array) - 从数组创建 Flux,数组作为整体一次性返回
  • fromStream(Stream<? extends T> s) - 从 Stream 创建 Flux
  • range(int start, int count) - 创建一个包含整数范围的 Flux
  • interval(Duration period) - 创建一个定期发射递增 Long 值的 Flux
  • empty() - 创建一个立即完成的空 Flux
  • error(Throwable error) - 创建一个立即错误终止的 Flux
  • never() - 创建一个不发射任何数据的 Flux

转换操作

  • map(Function<? super T, ? extends V> mapper) - 将元素转换为其他值
  • flatMap(Function<? super T, ? extends Publisher<? extends V>> mapper) - 将每个元素转换为 Publisher 并扁平化
  • concatWith(Publisher<? extends T> other) - 与另一个 Publisher 连接
  • mergeWith(Publisher<? extends T> other) - 与另一个 Publisher 合并
  • filter(Predicate<? super T> predicate) - 过滤元素
  • distinct() - 去除重复元素
  • take(long n) - 只取前 n 个元素
  • skip(long n) - 跳过前 n 个元素
  • buffer(int maxSize) - 将元素缓冲为集合
  • window(int maxSize) - 将元素窗口化为 Flux 的 Flux
  • zipWith(Publisher<? extends T2> source2, BiFunction<? super T, ? super T2, ? extends V> combinator) - 与另一个 Publisher 压缩

组合操作

  • zip(Publisher<? extends I> source1, Publisher<? extends I2> source2) - 将多个 Publisher 压缩为一个
  • merge(Publisher<? extends T>... sources) - 合并多个 Publisher
  • concat(Publisher<? extends T>... sources) - 顺序连接多个 Publisher

错误处理

  • onErrorResume(Function<? super Throwable, ? extends Publisher<? extends T>> fallback) - 错误时恢复
  • onErrorReturn(T fallbackValue) - 错误时返回默认值
  • onErrorMap(Function<? super Throwable, ? extends Throwable> mapper) - 转换错误
  • retry() - 重试订阅
  • retryWhen(Function, ? extends Publisher> whenFactory) - 条件重试

其他操作

  • subscribe() - 订阅 Flux
  • subscribe(Consumer<? super T> consumer) - 订阅并处理元素
  • blockFirst() - 阻塞直到第一个元素到达
  • blockLast() - 阻塞直到最后一个元素到达
  • log() - 记录所有信号
  • doOnNext(Consumer<? super T> onNext) - 元素到达时的副作用
  • doOnComplete(Runnable onComplete) - 完成时的副作用
  • doOnError(Consumer<? super Throwable> onError) - 错误时的副作用

Flux 和 Mono 都继承自 Publisher 接口,共享 subscribe 方法

反应式技术组件关系

Project Reactor

[Spring实现] Reactor 开源项目

Reactive Stream

Spring 反应式技术对比

想在 Spring 中实现响应式编程,需要使用到 Spring WebFlux,该组件是一个重新构建的基于 Reactive Streams 标准实现的异步非阻塞 Web 开发框架,以 Reactor 开发框架为基础,可以更加容易地实现高并发访问下的请求处理模型。

[理论] Servlet 3.x 异步编程 -> [Spring实现] Reactor 开源项目 -> [产品] WebFlux

传统请求处理:在 Servlet3.0 标准以前,每一个 Sevlet 都是采用 "Thread-Per-Request" (每个请求对应一个处理线程) 的方式进行请求处理。

异步请求处理:Servlet3.0 标准之后为了解决此类问题,提供了异步响应的支持。将耗时的操作部分交由一个专属的异步线程进行响应处理,同时请求线程资源将被释放,将该线程返回到线程池中。

posted @ 2025-06-04 17:14  千千菌  阅读(72)  评论(0)    收藏  举报