引言
Spring WebFlux基于Project Reactor实现,Reactor遵循Reactive Streams规范,通过发布者(Publisher)和订阅者(Subscriber)模式实现数据流的处理与传播,而Flux和Mono是Reactor中实现Reactive Stream规范的两个核心发布者类型。
Reactive Streams的标准:
-
Publisher(发布者) 数据提供者,提供给订阅者使用
-
Subscription(订阅) 订阅者订阅的发布者提供的数据
-
Subscriber(订阅者) 订阅发布者的数据
-
Processor(处理器) 这个接口集成了发布者和订阅者接口,所以处理器是发布者和订阅者都可以使用处理器
Mono和Flux
-
Flux:代表0个或N个元素的异步序列,适用于处理多元素场景
-
Mono:代表0个或1个元素的异步序列,适用于处理单元素或空值的场景
Mono和Flux操作符
Mono和Flux集成了大量操作符,这些操作符的存在减少了我们自定义 Subscriber 和 Processor 的需求。通过这些操作符的组合,我们可以直接对数据源和元素进行操作,而无需自己编写额外的 Processor 和 Subscriber
创建数据源(Flux,Mono)->转换和处理数据(map,filter…)->subscribe订阅数据源
一、创建操作符
Mono和Flux提供了很多创建数据源的方式,分为以下几类:
- 空数据源: 用于表示无数据的完成信号(如删除操作的结果)。
- 动态生成:Mono.create 和 Flux.generate/Flux.create 允许手动控制元素发射(同步或异步)。
- 异步数据源: 从 Future、Callable 或 Supplier 中获取数据,支持非阻塞操作。
- 时间驱动: Mono.delay 延迟发射,Flux.interval 周期性发射递增数值。
- 合并/组合: zip 严格对齐元素,merge 无序合并,concat 顺序连接。
- 背压适配: 通过 FluxSink 或 MonoSink 手动控制背压和元素发射。
类别 | 描述 | Mono方法示例 | Flux方法示例 |
---|---|---|---|
空数据源 | 创建不发射任何元素的数据源 | Mono.empty() | Flux.empty() |
单个元素 | 发射单个静态值或对象 | Mono.just(T) | Flux.just(T) |
多个元素 | 发射多个静态值或对象 | / | Flux.just(T1,T2…) |
集合/数组 | 以集合或数组中元素创建数据源 | / | Flux.fromIterable(List<T>) Flux.fromArray(T[]) |
流(Stream) | 以Java Stream中元素创建数据源 | / | Flux.fromStream(Stream<T>) |
序列 | 以整数序列来创建数据源 | / | Flux.range(start,count) |
动态生成 | 通过生成器函数动态生成元素来创建数据源 | Mono.create(sink -> {…}) | Flux.create(sink -> {…}) Flux.generate(sink -> {…}) |
异步数据源 | 从异步操作获取元素来创建数据源 | Mono.fromFuture(Future) Mono.fromCallable(Callable) | Flux.from(Publisher) Flux.fromStream(Supplier<Stream>) |
延迟初始化 | 延迟生成元素(在有订阅的时候才执行逻辑) | Mono.defer(() -> {…}) Mono.fromSupplier(Supplier) | Flux.defer(() -> {…}) Flux.fromStearm(Supplier<Stream>) |
时间驱动 | 基于时间生成元素 | Mono.delay(Duration) | Flux.interval(Duration) |
创建空数据源
//empty
Mono.empty().subscribe(System.out::println);
Flux.empty().subscribe(System.out::println);
//无任何输出
用已知的元素创建数据源
//just
Mono.just("hello Mono").subscribe(System.out::println);
//输出
//hello Mono
Flux.just("hello", "Flux").subscribe(System.out::println);
//输出
//hello
//Flux
以数组/集合/流中元素创建数据源
//数组
Flux.fromArray(new String[]{"hello", "flux", "array"}).subscribe(System.out::println);
//输出
//hello
//flux
//array
//集合
Flux.fromIterable(Arrays.asList("hello", "flux", "array")).subscribe(System.out::println);
//输出
//hello
//flux
//list
//流
Flux.fromStream(Stream.of("hello", "flux", "stream")).subscribe(System.out::println);
//输出
//hello
//flux
//stream
以整数序列创建数据源
//序列
Flux.range(0, 3).subscribe(System.out::println);
//输出
//0
//1
//2
动态创建数据源
Mono.create(monoSink -> {
monoSink.success("hello");
}).subscribe(System.out::println);
//输出
//hello
//生成一个偶数序列数据源
Flux.create(fluxSink -> {
for (int i = 0; i < 10; i++) {
if (i%2 ==0){
fluxSink.next(i);
}
}
fluxSink.complete();
}).subscribe(System.out::println);
//输出
//0
//2
//4
//6
//8
Flux.generate(() -> 0, (state , sink) -> {
if (state > 1 ){
sink.complete();
}
sink.next(state);
return ++state;
}).subscribe(System.out::println);
//输出
//0
//1
延时创建数据源
//延时5秒后发出一个Long值,从0开始
Mono.delay(Duration.ofMillis(5000)).subscribe(System.out::println);
//输出
//0
//间隔500ms,从0开始发送3个Long值
Flux.interval(Duration.ofMillis(500)).take(3).subscribe(System.out::println);
//输出
//0
//1
//3
//defer 在订阅时才创建数据源,Mono和Flux用法一致
Mono<Date> just = Mono.just(new Date());
Mono<Date> defer = Mono.defer(()->Mono.just(new Date()));
just.subscribe(System.out::println);
defer.subscribe(System.out::println);
//延迟5秒钟
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
just.subscribe(System.out::println);
defer.subscribe(System.out::println);
//输出,可以看到第一次创建的时间差不多,但是第二次defer会在订阅时再创建一个
//原因在于Mono.just会在声明阶段构造Date对象,只创建一次,但是Mono.defer却是在subscribe阶段才会创建对应的Date对象,每次调用subscribe方法都会创建Date对象
//Thu Jul 03 15:20:09 CST 2025
//Thu Jul 03 15:20:09 CST 2025
//Thu Jul 03 15:20:09 CST 2025
//Thu Jul 03 15:20:14 CST 2025
异步数据源
Mono.fromFuture(Future)
-
功能:将现有的
CompletableFuture
转换为Mono
,复用已有的异步计算结果。 -
执行机制:
- 即时触发:
Future
在创建时已开始执行,Mono
订阅时直接消费结果(无论是否完成)。 - 线程模型:依赖
Future
的线程池(如ForkJoinPool
),若任务阻塞则可能占用线程资源。
- 即时触发:
-
示例:
CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> "hello");
Mono<String> mono = Mono.fromFuture(future); // 立即执行 Future
mono.subscribe(System.out::println); // 输出 "hello"
Mono.fromCallable(Callable)
-
功能:将同步阻塞操作(如 I/O、计算)封装为惰性
Mono
,延迟执行直到订阅。 -
执行机制:
- 惰性触发:仅在
subscribe()
时调用Callable.call()
。 - 线程控制:需显式指定调度器(如
Schedulers.boundedElastic()
)避免阻塞响应式线程。
- 惰性触发:仅在
-
示例:
Mono<String> mono = Mono.fromCallable(() -> {
Thread.sleep(1000); // 模拟阻塞操作
return "hello";
}).subscribeOn(Schedulers.boundedElastic()); // 指定异步线程池
mono.subscribe(System.out::println); // 延迟1秒后输出