Mono<T>
和Flux<T>
是 ReactiveX for Java(RxJava)和 Project Reactor(Reactor)这两个响应式编程库中的核心抽象类型,尤其是在 Spring WebFlux 中得到广泛应用。
一、Mono 的常用方法
Mono<T>: 表示包含 0个或1个 元素的 异步序列。它用于表示将来某个时刻可能会产生单个值(也可能会产生空值)的异步操作结果。
1)创建 Mono:
Mono.just(T value)
:创建一个包含单个给定值的 Mono,创建出来的 Mono 序列在发布这些元素之后会自动结束。Mono.empty()
:创建一个不包含元素,只发布结束消息的 Mono。(在响应式编程中,流的传递是基于元素的,empty 表示没有元素,所以不会进行后续传递,需要使用 switchIfEmpty 进行处理。)Mono.never()
:empty 里面至少还有一个结束消息,而 never 则是真的啥都没有。Mono.error(Throwable error)
:创建一个包含给定错误的 Mono。Mono.defer(Callable<Mono<T>> supplier)
:延迟 Mono 的创建直到订阅时,此时 supplier 函数会被调用实际创建 Mono。示例如下:
Mono.defer(() -> {
return Mono.error(new RuntimeException);
}).subscribe();
Mono.fromCallable(Callable<T> callable)
:类似于 defer(),但它接受 Callable 并在订阅时执行,返回一个单一结果。使用示例:
Mono.fromCallable(() -> "9999").subscribe(System.out::println);
Mono.fromCompletionStage(CompletionStage<T> completionStage)
:从 CompletionStage 创建 Flux。Mono.fromFuture(CompletableFuture<T> future)
:从 Future 创建 Flux。Mono.fromRunnable(Runnable runnable)
:从 Runnable 创建 Flux。Mono.fromSupplier(Supplier<T> supplier)
:从 Supplier 创建 Flux。Mono.justOrEmpty(Optional<? extends T> data)
:从一个 Optional 对象中创建 Mono。只有 Optional 对象中包含值时,Mono 序列才产生对应的元素。Mono.justOrEmpty(T data)
:从一个 可能为 null 的对象中创建 Mono。只有对象不为 null 时,Mono 序列才产生对应的元素。Mono.create(Supplier<MonoSink<T>> sinkSupplier)
:用于手动控制 Mono 流程,通过 MonoSink 提供数据、完成、或抛出错误的能力。使用示例:
Mono.fromSupplier(() -> "Hello").subscribe(System.out::println);
Mono.justOrEmpty(Optional.of("Hello")).subscribe(System.out::println);
Mono.create(sink -> sink.success("Hello")).subscribe(System.out::println);
Mono.delay(Deration duration)
:创建一个 Mono 序列,在指定的延迟时间之后,产生数字 0 作为唯一值。Mono.delayMillis(long duration)
:同上,指定具体的毫秒数作为延迟时间。
2)转换和组合:
map(Function<T, R> mappper)
:应用于 Mono 中的数据并映射为新类型。flatMap(Function<T, Mono<R>> mapper)
:将 Mono 中的值转换为另一个 Mono,并扁平化结果。then(Mono<T> other)
:当 Mono 完成(成功或失败)时,继续订阅另一个 Mono。zipWith(Mono<?> otherMono, BiFunction<? super T, ?, U> zipper)
:将两个 Mono 结合在一起,使用 zip 函数合并结果。使用示例:
// 直接拼接 -> [a, c] [b, d]
Flux.just("a", "b")
.zipWith(Flux.just("c", "d"))
.subscribe(System.out::println);
// 按照制定规则拼接 -> a-c b-d
Flux.just("a", "b")
.zipWith(Flux.just("c", "d"), (s1, s2) -> String.format("%s-%s", s1, s2))
.subscribe(System.out::println);
Mono.zip(...Mono sources)
:合并多个 Mono,当所有 Mono 完成后聚合它们的结果。
3)订阅和消费:
subscribe(Consumer<? super T> consumer)
:订阅 Mono 并在接收到值时执行 Consumer。subscribe(Consumer<? super T> successHandler, Consumer<Throwable> errorHandler)
:添加成功和错误处理器。block()
:阻塞等待 Mono 完成并返回结果。(注意:在异步非阻塞环境下慎用)blockFirst()
:阻塞调用线程,直到发射出的第一个元素到达,返回返回该元素。如果没有元素发射,则会抛出 NoSuchElementException。(当用于 Mono 上时,效果与 block() 相同)blockLast()
:阻塞调用线程,直到异步序列完成并返回最后一个元素。如果没有元素发射,则会抛出 NoSuchElementException。(当用于 Mono 上时,效果与 block() 相同)
注意:
- 在 Project Reactor 中,
block()
、blockFirst()
、blockLast()
这些方法在阻塞期间会 持有主线程,可能导致 线程饥饿、响应延迟 等问题,特别是在处理大量数据或长时间运行的任务时。在大部分情况下,尽量避免在生产环境中使用这些方法,因为它们会破坏响应式编程的优势——非阻塞性
和背压
支持。在响应式编程中,通常建议使用subscribe()
方法注册回调函数以非阻塞方式处理异步结果。然而,在测试、初始化或者其他特殊情况中,有时确实需要获取一个同步的结果。
二、Flux 的常用方法
Flux<T>: 表示包含 0个或多个 元素的 异步序列。它用于处理连续的数据流,例如集合、数组或事件流。
1)创建 Flux:
Flux.just(T... values)
:创建一个包含一组值的 Flux,创建出来的 Flux 序列在发布这些元素之后会自动结束。Flux.fromArray(T[] array)
:从数组创建 Flux。Flux.fromIterable(Iterable<T> iterable)
:从 Iterable 对象创建 Flux。Flux.fromStream(Stream<T> strean)
:从 Stream 对象创建 Flux。Flux.empty()
:创建一个不包含任何元素,只发布结束消息的序列。(在响应式编程中,流的传递是基于元素的,empty 表示没有元素,所以不会进行后续传递,需要使用 switchIfEmpty 进行处理。)Flux.never()
:创建一个不包含任何元素的序列。Flux.error(Throwable error)
:创建一个只包含错误消息的序列。Flux.range(int start, int count)
:创建一个包含从 start 开始计数的 count 个整数的 Flux。使用示例:
Flux.range(1, 10)
.timeout(Flux.never(), v -> Flux.never()) // 表示永不超时
.subscribe(System.out::println);
Flux.interval(Duration period, Duration delay)
:创建一个按照固定时间间隔不断产生 Long 类型数值的 Flux 序列。这个序列可以用来做定时任务或者周期性触发某些操作。使用示例:
2)转换和过滤:
map(Function<T, R> mapper)
:映射每个元素到新的类型。filter(Predicate<T> predicate)
:根据给定谓词过滤元素。flatMap(Function<T, Publisher<R>> mapper)
:将每个元素转换为 Publisher 并扁平化结果。concatMap(Function<T, Publisher<R>> mapper)
:与 flatMap 类似,但保持顺序输出。
3)控制流:
limitRate(int maxConcurrency)
:限制并发订阅的数量。take(int n)
:仅取前 n 个元素。skip(int n)
:跳过前 n 个元素。buffer(int size)
:按指定大小
4)错误处理与完成:
onErrorResume(BiFunction<Throwable, ? super Flux<T>, ? extends Publisher<U>> resumeFunction)
:当 Flux 发生错误时,提供备用 Publisher 继续发射元素。doOnError(Consumer<Throwable> errorHandler)
:添加错误处理器。doOnComplete(Runnable onCompleteHook)
:在 Flux 完成时执行一个钩子方法。
5)订阅和消费:
subscribe(Consumer<? super T> consumer)
:订阅 Flux 并在接收到每个元素时执行 Consumer。subscribe(Consumer<? super T> onNext, Consumer<Throwable> onError, Runnable onComplete)
:添加完整订阅处理器,包括正常接收、错误处理和完成时的回调。block()
:阻塞等待 Flux 完成并返回结果。(注意:在异步非阻塞环境下慎用)blockFirst()
:阻塞调用线程,直到发射出的第一个元素到达,返回返回该元素。如果没有元素发射,则会抛出 NoSuchElementException。blockLast()
:阻塞调用线程,直到异步序列完成并返回最后一个元素。如果没有元素发射,则会抛出 NoSuchElementException。
注意:
- 在 Project Reactor 中,
block()
、blockFirst()
、blockLast()
这些方法在阻塞期间会 持有主线程,可能导致 线程饥饿、响应延迟 等问题,特别是在处理大量数据或长时间运行的任务时。在大部分情况下,尽量避免在生产环境中使用这些方法,因为它们会破坏响应式编程的优势——非阻塞性
和背压
支持。在响应式编程中,通常建议使用subscribe()
方法注册回调函数以非阻塞方式处理异步结果。然而,在测试、初始化或者其他特殊情况中,有时确实需要获取一个同步的结果。
6)组合和订阅:
mergeWith(Flux<? extends T> other)
:合并两个 Flux 流。reduce(BiFunction<T, T, T> accumulator)
:对整个序列应用一个累加器函数,返回单一结果。
整理完毕,完结撒花~🌻
参考地址:
1.Mono和Flux的用法详解,https://blog.csdn.net/lz710117239/article/details/93777692