Spring WebFlux学习笔记(二)Mono和Flux操作符

引言

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提供了很多创建数据源的方式,分为以下几类:

  1. 空数据源: 用于表示无数据的完成信号(如删除操作的结果)。
  2. ‌动态生成:Mono.create 和 Flux.generate/Flux.create 允许手动控制元素发射(同步或异步)。
  3. ‌异步数据源: 从 Future、Callable 或 Supplier 中获取数据,支持非阻塞操作。
  4. ‌时间驱动: Mono.delay 延迟发射,Flux.interval 周期性发射递增数值。
  5. ‌合并/组合: zip 严格对齐元素,merge 无序合并,concat 顺序连接。
  6. ‌背压适配: 通过 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秒后输出
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值