【参考资料】
【1】https://developer.ibm.com/zh/articles/j-cn-with-reactor-response-encode/
【2】https://blog.csdn.net/tonydz0523/article/details/107858943
【3】https://www.jianshu.com/p/611f3667c4d2
【4】https://www.cnblogs.com/todev/p/13182162.html
【5】https://projectreactor.io/docs/core/release/api/
【6】《Java 设计模式与实践》
1. 基本概念
1.0 响应式编程
-
响应式编程是一种编程范式,基于异步数据流,包含四大主旨:
响应性:系统能够以一致且可预测的方式及时响应。
可恢复性:系统能够快速地从故障中恢复。
弹性:系统能够动态地查找和修复性能瓶颈,不同于可扩展性,弹性系统是根据需求【动态】调整。
消息驱动:系统依赖于异步消息传递机制,能够确保其松耦合、相互隔离、位置透明和具有容错能力。 -
响应式编程从设计角度讲,通常基于观察者模式出现,以数据“推”的方式进行
-
响应式编程是lazy的,只有当数据流被订阅才触发,本质是subscriber发出一个request,然后层层上传至publisher
-
响应式编程的subscriber在发送request时可以限制数据量以实现背压
1.1 Flux
Flux 属于一个publisher,能够发出 0 到 N 个元素的标准 Publisher,它会被一个完成(completion)或错误(error)信号终止
1.2 Mono
Mono 属于一个特殊的publisher,只能发出1个元素
2. 发射器创建
2.1 Flux 静态创建
2.1.1 just/fromArray/range
Flux.just("test1", "test2", 1).subscribe(System.out::println);
Flux.fromArray(new Integer[] {1, 2, 3}).subscribe(System.out::println);
Flux.range(1, 10).subscribe(System.out::println);
2.1.2 interval
//参数1是delay,参数2是interval
Flux.interval(Duration.of(10, ChronoUnit.SECONDS),
Duration.of(1, ChronoUnit.SECONDS)).subscribe(new Consumer<Long>() {
@Override
public void accept(Long aLong) {
System.err.println("empty message!!" + aLong);
}
});
输出:
2.2 Flux 动态创建
2.2.1 generate
public static <T, S> Flux<T> generate(@NotNull java.util.concurrent.Callable<S> stateSupplier,
@NotNull
java.util.function.BiFunction<S, reactor.core.publisher.SynchronousSink<T>, S> generator,
@NotNull java.util.function.Consumer<? super S> stateConsumer)
1、在generator中会有一个state维护,由stateSupplier初始化,由 stateConsumer 消费最后的结果
2、generator只能创建Flux,不能创建Mono
Flux.generate(
()-> 0,
(i, sink) -> {
sink.next(i);
if (i == 5) sink.complete();
return ++i;
},
state -> System.err.println("end is : " + state)
).subscribe(System.out::println);
输出:
Flux.generate(
ArrayList::new,
(list, sink) -> {
Float item = new Random().nextFloat();
sink.next(item);
list.add(item);
if (list.size() == 5) sink.complete();
return list;
},
state -> System.err.println("end is : " + state.size())
).subscribe(System.out::println);
输出:
2.2.2 create
Flux.create(sink -> {
for (int i = 0; i < 5 ; i++) {
sink.next(i);
}
//sink.error(new RuntimeException("Error"));
sink.complete();
}).subscribe(System.out::println);
2.3 Mono 动态创建
Mono.create(sink -> {
List<Integer> list = new ArrayList<>();
for (int i = 0; i < 5 ; i++) {
list.add(i);
}
sink.success(list);
}).subscribe(System.out::println);
输出:[0, 1, 2, 3, 4]
3. 操作符
此处对操作符的记录以Flux为主,Mono的操作符是Flux的一个子集
类型 | 操作符 |
---|---|
转换 | as, cast, collect, collectList, collectMap, collectMultimap, collectSortedList, concatMap, concatMapDelayError, concatMapIterable, elapsed, expand, expandDeep, flatMap, flatMapDelayError, flatMapIterable, flatMapSequential, flatMapSequentialDelayError, groupJoin, handle, index, join, map, switchMap, switchOnFirst, then, thenEmpty, thenMany, timestamp, transform, transformDeferred |
筛选 | blockFirst, blockLast, distinct, distinctUntilChanged, elementAt, filter, filterWhen, ignoreElements, last, next, ofType, or, repeat, retry, single, singleOrEmpty, sort, take, takeLast, takeUntil, takeUntilOther, takeWhile |
组合 | concatWith, concatWithValues, mergeOrderWith, mergeWith, startWith, withLatestFrom, zipWith, zipWithIterable |
条件 | defaultIfEmpty, delayUntil, retryWhen, switchIfEmpty |
时间 | delayElements, delaySequence, delaySubscription, sample, sampleFirst, sampleTimeout, skip, skipLast, skipUntil, skipUntilOther, skipWhile, timeout |
统计 | count, reduce, reduceWith, scan, scanWith |
匹配 | all, any, hasElement, hasElements |
分组 | buffer, bufferTimeout, bufferUntil, bufferUntilChanged, bufferWhen, groupBy, window, windowTimeout, windowUntil, windowUntilChanged, windowWhen, windowWhile |
事件 | doAfterTerminate, doFinally, doFirst, doOnCancel, doOnComplete, doOnDiscard, doOnEach, doOnError, doOnNext, doOnRequest, doOnSubscribe, doOnTerminate, onBackpressureBuffer, onBackpressureDrop, onBackpressureError, onBackpressureLatest, onErrorContinue, onErrorMap, onErrorResume, onErrorReturn, onErrorStop |
调试 | checkpoint, hide, log |
其它 | cache, dematerialize, limitRate, limitRequest, materialize, metrics, name, onTerminateDetach, parallel, publish, publishNext, publishOn, replay, share, subscribeOn, subscriberContext, subscribeWith, tag |
3.1 转换操作符
Flux.range(1, 3)
.collectList()
.subscribe(System.out::println);
List<Employee> list = new ArrayList<>();
list.add(new Employee("fred", 10));
list.add(new Employee("siiny", 11));
Flux.fromIterable(list)
.collectMap(key -> key.getName(), val -> val.getWorkYear())
.subscribe(System.out::println);
输出:
3.2 筛选操作符
filter中传入的是一个Predicate
reactor.core.publisher.Flux<T> public final Flux<T>
filter(@NotNull java.util.function.Predicate<? super T> p
List<Employee> list = new ArrayList<>();
list.add(new Employee("fred", 10));
list.add(new Employee("siiny", 11));
Flux.fromIterable(list)
.filter(item -> item.getWorkYear() > 10)
.subscribe(System.out::println);
输出:
3.3 组合操作符
List<Employee> list1 = new ArrayList<>();
list1.add(new Employee("fred", 10));
list1.add(new Employee("siiny", 11));
List<Employee> list2 = new ArrayList<>();
list2.add(new Employee("william", 2));
Flux<Employee> flux1 = Flux.fromIterable(list1);
Flux<Employee> flux2 = Flux.fromIterable(list2);
Flux<Employee> merge = flux1.mergeWith(flux2);
merge.subscribe(System.out::println);
输出:
3.4 条件操作符
List<Employee> list = new ArrayList<>();
list.add(new Employee("fred", 10));
list.add(new Employee("sinny", 11));
list.add(new Employee("william", null));
Flux.empty().defaultIfEmpty(3).subscribe(System.out::println);
Flux.empty().switchIfEmpty(Flux.fromIterable(list)).collectList().subscribe(System.out::println);
输出:
3.5 时间操作符
Flux.fromIterable(list).skip(1).skipLast(1).subscribe(System.out::println);
//根据周期采样
Flux.interval(Duration.ofSeconds(1)).sample(Duration.ofSeconds(3)).subscribe(System.out::println);
Flux.interval(Duration.ofSeconds(1)).sampleFirst(Duration.ofSeconds(3)).subscribe(System.out::println);
输出:
1 4 7 或 0 4 8
3.6 统计操作符
List<Employee> list = new ArrayList<>();
list.add(new Employee("fred", 10));
list.add(new Employee("sinny", 11));
list.add(new Employee("william", 5));
Flux.fromIterable(list).map(val -> val.getWorkYear()).reduce((x, y) -> x + y).subscribe(System.out::println);
Flux.fromIterable(list).count().subscribe(System.out::println);
输出:26 和 3
3.7 匹配操作符
List<Employee> list = new ArrayList<>();
list.add(new Employee("fred", 10));
list.add(new Employee("sinny", 11));
list.add(new Employee("william", 5));
Flux.fromIterable(list).all(val -> val.getWorkYear() > 10).subscribe(System.out::println);
Flux.fromIterable(list).any(val -> val.getWorkYear() > 10).subscribe(System.out::println);
输出:false 和 true
3.8 分组操作符
Flux.range(1, 10)
.groupBy(i -> i % 2 == 0 ? "even" : "odd").subscribe(flux -> flux.count().subscribe(System.out::println));
Flux.range(1, 10)
.groupBy(i -> i % 2 == 0 ? "even" : "odd", i ->i).concatMap(flux -> flux.count())
.subscribe(System.out::println);
Flux.range(1, 10)
.collectMultimap(i -> i % 2 == 0 ? "even" : "odd")
.map(item -> {
Map<String, Integer> data = new HashMap<>();
item.keySet().forEach(key -> data.put(key, item.get(key).size()));
return data;
}).subscribe(System.out::println);
输出:
3.9 事件操作符
Flux.range(1,10)
.map(i -> {
if (i == 5) throw new RuntimeException("error");
else return String.valueOf(i);
})
.doOnError(error -> System.err.println("doOnError " + error.getMessage()))
.doOnNext(info -> System.err.println("doOnNext " + info))
.doOnComplete(() -> System.err.println("doOnComplete ")) // 因为error没有完成不触发
.doOnTerminate(() -> System.err.println("doOnTerminate ")) // 无论完成与否,只要终止就触发
.subscribe();
输出:
此处加入一个retry的例子,当发生错误时允许重试
Flux.range(1,10)
.map(i -> {
if (i == 5) throw new RuntimeException("error");
else return String.valueOf(i);
}).retry(1)
.doOnError(error -> System.err.println("doOnError " + error.getMessage()))
.doOnNext(info -> System.err.println("doOnNext " + info))
.doOnComplete(() -> System.err.println("doOnComplete ")) // 因为error没有完成不触发
.doOnTerminate(() -> System.err.println("doOnTerminate ")) // 无论完成与否,只要终止就触发
.subscribe();
输出:
4. 调度器
Schedulers 是 reactor中提供的并发方式,主要有如下调度机制:
调度方式 | 描述 |
---|---|
Schedulers.immediate() | 使用当前线程 |
Schedulers.elastic() | 使用线程池 |
Schedulers.newElastic(“test1”) | 使用新线程池 |
Schedulers.single() | 单个线程 |
Schedulers.newSingle(“test1”) | 使用新线程 |
Schedulers.parallel() | 使用并发线程池,与CPU核一致 |
Schedulers.newParallel(“test1”) | 使用新并发线程池,与CPU核一致 |
Schedulers.fromExecutorService(Executors.newScheduledThreadPool(5)) | 使用自定义线程池 |
Flux.range(1,3)
.map(i -> {
System.err.println("Map 1 " + Thread.currentThread().getName() + " " + i);
doLongCalc();
return i*i;
})
.publishOn(Schedulers.newParallel("newParallel")) //影响其之后的操作符
.map(i -> {
System.err.println("Map 2 " + Thread.currentThread().getName() + " " + i);
doLongCalc();
return -i;
})
.map(i -> {
System.err.println("Map 3 " + Thread.currentThread().getName() + " " + i);
doLongCalc();
return (i+2) + "";
})
.subscribe(System.err::println);
输出:
5. 背压
利用 BaseSubscriber 进行背压,限制处理的数量。BaseSubscriber是Subscriber的实现,支持用户直接操作
request和cancel。
其实现方式是重写钩子函数,包括
hookOnComplete()
hookOnError(Throwable)
hookFinally(SignalType)
hookOnCancel()
Flux<Integer> flux = Flux.range(1,5).log();
flux.subscribe(new BaseSubscriber<Integer>() {
private int count = 0;
private final int requestCount = 2;
@Override
protected void hookOnSubscribe(Subscription subscription) {
request(requestCount);
}
@SneakyThrows
@Override
protected void hookOnNext(Integer value) {
count++;
if (count == requestCount) {
Thread.sleep(1000);
request(requestCount);
count = 0;
}
}
});
输出:
此处限制每次取2个元素进行处理