projectreactor.io官网学习笔记
package com.webflux.fluxtest.controller;
import lombok.extern.slf4j.Slf4j;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
import reactor.core.publisher.SynchronousSink;
import reactor.core.scheduler.Scheduler;
import reactor.core.scheduler.Schedulers;
import java.time.Duration;
import java.util.*;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicReference;
import java.util.stream.Stream;
/**
* @Author lemon
* @Date 2021/6/15 16:12
*/
@RestController
@Slf4j
public class CreateTest {
@GetMapping("/test")
public Flux<String> test() {
return null;
}
private static AtomicReference<SynchronousSink> sinks = new AtomicReference<>();
public static void main(String[] args) throws Exception {
List<String> l1 = Arrays.asList("1", "2", "3");
List<String> l2 = Arrays.asList("4", "5", "6");
Flux<Integer> range = Flux.range(100, 10)/*.doOnNext(System.out::println).doOnComplete(() -> System.out.println("OK"))*/;
Flux<Integer> range1 = Flux.range(1000, 10)/*.doOnNext(System.out::println).doOnComplete(() -> System.out.println("OK"));*/;
Mono<String> just = Mono.just("100");
Mono<String> mono = Mono.fromCallable(() -> "this is running");
mono.subscribeOn(Schedulers.boundedElastic())
.delayElement(Duration.ofSeconds(1))
.doOnNext(System.out::println)
.subscribe();
log.info("123");
// System.in.read();
}
/**
* 异常处理
*/
private static void testError() {
Flux<Integer> range = Flux.range(100, 10)/*.doOnNext(System.out::println).doOnComplete(() -> System.out.println("OK"))*/;
//timeout标识,如果在指定时间内,没有发射元素,则抛出超时异常,注意:不是总运行时间
//补充: delayElements(duration)方法是延迟发射元素,异步执行,默认是守护线程执行。可以参数设置执行线程方式
// Flux.range(0,10).delayElements(Duration.ofMillis(100), Schedulers.newParallel("test", 10, false))
// .doOnNext(System.out::println)
// .timeout(Duration.ofMillis(50))
// .subscribe();
//onErrorMap 将序列运行中抛出的异常处理后返回一个新的异常
// range.onErrorMap(e -> new RuntimeException("统一抛出一个异常")).subscribe();
range.map(it -> {
if(it == 105) {
it = it / 0;
}
return it;
})
// .doOnNext(System.out::println)
.onErrorMap(e -> new RuntimeException("运行中异常"))
.onErrorContinue((e,it) -> System.out.println(it + "运行异常,e=" + e.getMessage()))
//如果异常,重试次数,默认无限重试
// .retry(10)
.subscribe(System.out::println);
}
/**
* 序列的过滤操作
* take、filter、skip、sample
*/
private static void testFileter() {
Flux<Integer> range = Flux.range(100, 10)/*.doOnNext(System.out::println).doOnComplete(() -> System.out.println("OK"))*/;
//将上游的数据进行类型判断,符合该类型的数据将流向下游
// range.ofType(String.class).doOnNext(System.out::println).subscribe();
//过滤数据
// range.filter(it -> it > 105).subscribe();
//将重复数据过滤,重复数据在整个序列中只保留一个
// range.concatWith(Flux.just(100,100,100)).distinct().doOnNext(System.out::println).subscribe();
//将后来的重复数据过滤,如下,第二个flux拼接到第一个序列时,只会把第二个元素本身的重复元素过滤
// range.concatWith(Flux.just(100,100,100)).distinctUntilChanged().doOnNext(System.out::println).subscribe();
//在序列的开始获取5个元素,
// limitRequest为true时,则不管该序列会发射多少元素,该参数会向上传递背压,则上游序列只会发出设定的5个元素
//为false时,则不控制上有元素可以发出N个元素
// range.take(5, false).subscribe(System.out::println);
//参数为时间单位,意味着take获取元素,只会在改时间限制内获取。
// range.take(Duration.ofSeconds(1)).subscribe(System.out::println);
//获取最后的N位元素
// range.takeLast(2).subscribe(System.out::println);
//获取元素,知道符合条件后停止向下游发送数据,包括条件本身,也就是当it>105的元素也会被发布至下游
// range.takeUntil(it -> it>105).subscribe(System.out::println);
//获取元素,当元素符合该断言时,如果不符合直接终止,不包含条件本身
// range.takeWhile(it -> it < 105).subscribe(System.out::println);
//获取指定某个位置的一个元素
// range.elementAt(0).subscribe(System.out::println);
//获取最后一个元素,last()如果为空则抛出异常,last(1)如果为空则发出默认值
// range.takeWhile(it -> it > 105).last(1).subscribe(System.out::println);
//跳至第几秒开始执行
// range.skip(Duration.ofSeconds(5)).subscribe(System.out::println);
//跳至第几个元素开始执行
// range.skip(5).subscribe(System.out::println);
//从开始跳到最后第N个元素结束
// range.skipLast(5).subscribe(System.out::println);
//跳至满足条件的地方开始执行,从第一个元素开始,知道满足条件,开始发送至下游
// range.skipUntil(it -> it > 105).subscribe(System.out::println);
//每隔一段时间抽取样本数(取在这个时间的最后一个元素),如果相隔实现大于序列的执行时间,则去最后一元素
// Flux.range(100, 100000000).sample(Duration.ofMillis(100)).subscribe(System.out::println);
//每隔一段时间抽取样本数(取在这个时间的第一个元素),如果相隔实现大于序列的执行时间,则取第一个元素
// Flux.range(100, 10).sampleFirst(Duration.ofMillis(100)).subscribe(System.out::println);
//只获取一个元素,single()如果为空或者超多一个,抛出异常,single(1)如果为空返回默认值,如果多个抛出异常,singleOrEmpty()可以允许为空
// range.single(1).subscribe(System.out::println);
}
/**
* 序列在执行时的一些监听方法doOnXXXX
*/
private static void testDoOn() {
Flux<Integer> range = Flux.range(100, 10).doOnNext(System.out::println).doOnComplete(() -> System.out.println("OK"));
//执行当前序列中的元素consumer
// range.doOnNext(it -> System.out.println(it));
// range.doFirst(() -> System.out.println("第一个执行开始")).subscribe();
// range.doFinally(it -> System.out.println("终止信号的类型为" + it.name())).subscribe();
// range1.doOnSubscribe(it -> System.out.println("该序列已被订阅")).subscribe();
// range.doOnRequest(value -> System.out.println(value)).subscribe();
//在完成或者error时,也就是序列终止时执行runnable
// range.doOnTerminate(() -> System.out.println("OVER")).subscribe();
//doOnEach每次向下游传播,都会得到一个信号类型,可以根据该信号类型执行一些操作
// range.doOnEach(it -> System.out.println(it)).subscribe();
}
/**
* then按照执行的规则返回mono或者flux
*/
private static void testThen() {
Flux<Integer> range = Flux.range(100, 10).doOnNext(System.out::println).doOnComplete(() -> System.out.println("OK"));
Flux<Integer> range1 = Flux.range(1000, 10)/*.doOnNext(System.out::println).doOnComplete(() -> System.out.println("OK"));*/;
//讲一个publisher终止为一个mono<Void>
range.then();
//将当前publisher发射完成后,执行thenEmpty(publisher)返回一个mono<Void>,并订阅publisher
range.thenEmpty(range1.then()).subscribe();
//thenMany可以返回多个的FLUX类型
range.thenMany(range1).doOnNext(System.out::println).subscribe();
}
/**
* 处理空值
*/
private static void testEmpty() {
//如果序列是个空的,就给个默认值
Flux.empty().defaultIfEmpty(1).doOnNext(System.out::println).subscribe();
//如果序列是空的,就用新序列代替
Flux.empty().switchIfEmpty(Mono.just("100")).doOnNext(System.out::println).subscribe();
}
/**
* 重复执行
*/
private static void testRepear() {
Flux<Integer> range = Flux.range(100, 10);
//repeat会一直重复执行range中的元素,该方法可以有一个断言的参数实现
range.repeat().doOnNext(System.out::println).subscribe();
Flux.interval(Duration.ofSeconds(1)).doOnNext(System.out::println).subscribe();
}
/**
* 将两个序列进行合并的API
*/
private static void testConcat() {
Flux<Integer> range = Flux.range(100, 10);
Mono<String> just = Mono.just("100");
Flux<Integer> integerFlux = range
.map(it -> {
if (it == 105) {
// it = it/0;
}
it = it + 1000;
return it;
});
// .onErrorContinue((e, it) -> {
// System.out.println(e.getMessage());
// System.out.println(it);
// });
// concat会中断主序列,也就是说,如果在integerFlux中出现了异常,就不会链接just
// Flux.concat(integerFlux, just).subscribe(System.out::println);
//合并两个序列,如果异常,中断
// integerFlux.concatWith(just).subscribe(System.out::println);
// concatDelayError不会中断主序列,也就是说,如果在integerFlux中出现了异常,先不抛出,而是在链接完just后抛出
// Flux.concatDelayError(integerFlux, just).subscribe(System.out::println);
//按照数据合并
// Flux.mergeSequential(integerFlux, just).subscribe(System.out::println);
//合并两个序列,无序
// Flux.merge(integerFlux, just).subscribe(System.out::println);
//合并两个序列,无序
// integerFlux.mergeWith(just).subscribe(System.out::println);
//将两个序列合并,最多参数为8个,返回值为TupleX类型,被拼接的第一个就是T1,第二个就是T2,第三个就是T3...
// Flux.zip(integerFlux,integerFlux).doOnNext(System.out::println)
// .subscribe();
//将多个序列拼接,并且按照function的算法,完成拼接,下面是将多个序列相加返回,如果异常,则zip失败,数据不会流向下游
// Flux.<Integer, Integer>zip(it -> {
// return Arrays.stream(it).map(its -> (Integer)its).reduce(Integer::sum).orElseGet(() -> 0);
// }, integerFlux,integerFlux)
// .doOnNext(System.out::println)
// .subscribe();
//将多个序列完成拼接,返回的是Tuple2<T, T2>
// integerFlux.zipWith(range).doOnNext(it -> System.out.println(it.getT1()))
// .subscribe();
//firstWithValue 是将publisher集合中的第一个集合发送给下游
// List<Flux<Integer>> list = new ArrayList<>();
// list.add(integerFlux);
// list.add(range);
// Flux.firstWithValue(list).doOnNext(System.out::println)
// .subscribe();
//将某个flux讲过处理后,返回一个新类型的flux
range.switchMap(it -> Flux.just(it + it + "相加完成")).doOnNext(System.out::println)
.subscribe();
}
/**
* 在开始和结束添加元素
*/
private static void testStartAndConcatWith() {
Flux.range(100, 10)
//在publish的开始添加元素
.startWith(888, 999, 777)
//在最后添加元素
.concatWithValues(888, 999, 777)
.subscribe(System.out::println);
}
/**
* 将两个publish拼接起来,并且按照一定的拼接规则
* return :
* 988
* 1100
*/
private static void testZipWith() {
Flux.range(100, 10)
.zipWith(Flux.just(888, 999), Integer::sum)
.doOnNext(System.out::println)
.subscribe();
}
/**
* index方法用于flux的下标获取,getT1=所有下标的集合,getT2=所有值得集合
* return:
* 100
* 101
* 102
* 103
* 104
* ...
* 109
*/
private static void testIndex() {
Flux.range(100, 10)
.index()
.doOnNext(it -> System.out.println(it.getT2()))
.subscribe();
}
/**
* 将上游数据重新开启window处理,返回的是一个新的flux<>
*/
private static void testWindow() {
Flux.interval(Duration.ofSeconds(1))
//将上游数据收集成一个新的flux<>来执行,相当于每几个开一个窗口执行,收集完成后发送给下游一个flux<>, skip表示每隔几个进行分组
.window(2, 1)
//将上游数据进行收集,当满足条件后,将之前收集到的数据打包发送给下游
// .windowUntil(it -> it % 2 == 0)
//将上游数据进行过滤,如果满足添加,将当前数据立马发送给下游
// .windowWhile(it -> it % 2 ==0)
// .take(3)
.doOnNext(it -> it.collectList().doOnNext(System.out::println).subscribe())
.subscribe();
}
/**
* 将上游数据重新开启window处理,返回的是一个 list 或者 T
*/
private static void testBuffer() {
Flux.interval(Duration.ofSeconds(1))
//三个一组缓存,每一组缓存间隔1个元素,下面将输出:[012],[123],[234],
// 所谓的skip是指每组元素的第一个跟第二组元素的第一个相隔的数值
.buffer(3, 1)
//超时时间:意思是没3个完成一次缓存,发放至下游,如果在1500毫秒内没有完成,则强制流向下游
// .bufferTimeout(3, Duration.ofMillis(1500))
//缓存会一直收集,只有当满足条件时,停止收集,并【一起】发送给下游
// .bufferUntil(it -> it == 10)
//当缓存收集到符合该条件时,会将当前值立即发送给下游
// .bufferWhile(it -> it%2==0)
// .take(3)
.doOnNext(System.out::println)
.subscribe();
}
/**
* transform:接受一个flux 返回一个flux,相比于flatmap,他传入的参数是一个flux对象,flatmap传入的是flux的object
* 都是处理逻辑功能
*/
private static void testTransform() {
AtomicInteger ai = new AtomicInteger();
Flux.fromIterable(Arrays.asList("blue", "green", "orange", "purple"))
.doOnNext(System.out::println)
// .transform(it -> {
// return it.map(aa -> aa.toUpperCase());
// })
// .flatMap(it -> {
// return Mono.just(it.toUpperCase());
// })
.transformDeferred(f -> {
if (ai.incrementAndGet() == 1) {
return f.filter(color -> !color.equals("orange"))
.map(String::toUpperCase);
}
return f.filter(color -> !color.equals("purple"))
.map(String::toUpperCase);
})
.subscribe(d -> System.out.println("Subscriber to Transformed MapAndFilter: " + d));
}
/**
* 当被订阅后如果发生异常,则stream会停止运行
* 此时可以通过处理error来决定如何处理异常
* 可以将异常跳过、将异常替换等
*/
private static void testErrorHandle() {
Flux.just(1, 2, 3, 0, 5, 4).map(it -> {
it = 100 / it;
return it;
})
//报错后继续运行,并执行相关操作
// .onErrorContinue((e, it) -> {
// System.out.println(e.getMessage());
// })
//报错后停止运行
// .doOnError(System.out::println)
//报错后返回,并停止运行
// .onErrorResume(e -> {
// System.out.println(e.getMessage());
// return Mono.just(100000000);
// })
//保存后返回替换,并停止运行
// .onErrorReturn(1000000)
.onErrorResume(e -> {
return Mono.just(10000);
})
.doFinally(type -> {
System.out.println(type);
})
.subscribe(System.out::println);
}
/**
* publishOn会在下游执行时,按照指定的线程来执行,下例中,
* 第一个map运行在主线程中,第二个map运行在指定的test-线程中
*
* @param range .
*/
private static void testPublistOn(Flux<Integer> range) {
Scheduler s = Schedulers.newParallel("test-", 10, false);
/*Flux<Integer> flux = */
range.map(it -> it + 10)
.publishOn(s)
.map(it -> it + 100)
.log()
.subscribe(System.out::println);
// new Thread(() -> {
// flux.subscribe(System.out::println);
// });
// System.in.read();
}
private static void testSubscribe(Flux<Integer> range) {
range.subscribe(
System.out::println,
e -> System.out.println("error" + e),
() -> System.out.println("DONE")
);
}
/**
* flatMapSequential能够保证多线程运行的顺序行,并且能够在异步完成
* 既能保证效率,又能保证顺序性
*/
private static void testSequential() {
List<String> employeeIds = Arrays.asList("1", "2", "3", "4", "5", "6", "7", "8");
Flux.fromIterable(employeeIds)
// .parallel()
// .runOn(Schedulers.newParallel("test-"))
// .window(2)
// .flatMapSequential(it -> it.parallel().runOn(Schedulers.newParallel("test-")).flatMap(CreateTest::getEmployeeName))
// .map(Flux::just)
.window(2)
.flatMapSequential(it -> it.parallel().runOn(Schedulers.newParallel("")).flatMap(CreateTest::getEmployeeName))
.doOnNext(System.out::println).subscribe();
}
private static Mono<String> getEmployeeName(String id) {
Map<String, String> employees = new HashMap<>();
employees.put("1", "aSha");
employees.put("2", "billy");
employees.put("3", "cindy");
employees.put("4", "davide");
employees.put("5", "ella");
employees.put("6", "flee");
employees.put("7", "galosh");
employees.put("8", "hank");
String name = employees.get(id);
try {
// Thread.sleep(new Random().nextInt(100)*100);
Thread.sleep(1000);
} catch (InterruptedException e) {
throw new RuntimeException("Thread sleep Error!!!");
}
if (!StringUtils.hasText(name)) {
throw new RuntimeException("Not Found!!!");
}
log.info("id={}, name={}", id, name);
return Mono.just(name);
}
/**
* handle操作类似于stream的map+filter,
* handle会将上游的数据便利,第一个参数就是上游数据,第二个参数是sink发射给下游使用的
* 可以对上游数据进行过滤,转化,处理后按照需要发射给下游。
* 如下,则将只会在上游数据=105时发射数据,也就是下游数据只有123
*/
private static void testHandle() {
Flux.range(100, 10).handle(
(str, str1) -> {
if (str == 105) {
str1.next("123");
}
}
).doOnNext(System.out::println)
.subscribe();
}
private static <T> void print(T t) {
System.out.println(Thread.currentThread().getName() + " " + t);
}
/**
* map对流中的内容进行一顿操作
* flatmap 的返回值就是流的类型 例: Flux<List<Integer></>> flux.flatmap(it -> flux.from(it)) </>
* 此时flux.from返回的就是Flux<Integer>类型,则返回给flux对象也就是flux<Integer>类型了
*/
private static void testMapAndFlatMap() {
Flux.just(Arrays.asList(123, 123), Arrays.asList(123), Arrays.asList(123, 123), Arrays.asList(123))
// .flatMap(Flux::fromIterable)
// .map(Flux::just)
.flatMap(Flux::fromIterable)
// .flatMap(it -> it)
// .map(it -> Flux.fromIterable(it))
//
// .flatMap(it -> it)
.doOnNext(System.out::println)
.subscribe();
// .flatMap(it -> Flux.fromIterable(it))
// .map()
}
/**
* create方法,可以执行多次next,并且不会一直执行下去
* 可以在Consumer中创建线程,或者执行多次next发射值。只会执行一次
* 官方解释: 异步(也可以是同步),一次可以进行多次发射
*/
private static void testCreate() {
ArrayList<String> list = new ArrayList<>();
Flux.create(sink -> {
list.add(sink.next("123").toString());
list.add(sink.next("123").toString());
list.add(sink.next("123").toString());
list.add(sink.next("123").toString());
list.add(sink.next("123").toString());
list.add(sink.next("123").toString());
list.add(sink.next("123").toString());
list.add(sink.next("123").toString());
}).doOnNext(it -> {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(it);
})
.subscribe();
}
/**
* flux的generate创建publisher实例,只能调用一次SynchronousSink的方法,需要显式的
* 调用complate或者error完成停止发射数据
* callAble()返回值,提供给Bifunction来使用。
* 返回类型为SynchronousSink的泛型
*/
private static void testGenerate() {
// Flux<Object> log = Flux.generate(
// () -> 0,
// (i, sink) -> {
// sink.next(i * i);
// if (i == 5) sink.complete();
System.out.println(i);
// return ++i;
// },
// state -> CreateTest.log.warn("the final state is:{}", state)
// ).log();
//state会记录最后一次状态值
// log.subscribe();
/*Flux.generate((SynchronousSink<Integer> synchronousSink) -> {
synchronousSink.next(1);
})
.doOnNext(number -> System.out.println(number))
.doOnNext(number -> System.out.println(number + 4))
.subscribe();*/
Flux.generate(
() -> 1,
(s, sink) -> {
sink.next(10);
// sink.next(12);
if (s == 5) {
sink.complete();
}
return ++s;
}
).subscribe();
}
/**
* defer 会在调用subscribe()时初始化mono中的值,相当于懒加载
* fromSupplier() API同样会懒加载,因为supplier会在使用时调用get方法
*
* @throws Exception
*/
public static void testDefer() throws Exception {
Mono<Date> m1 = Mono.just(new Date()).doOnNext(System.out::println);
Mono<Date> m2 = Mono.defer(() -> Mono.just(new Date())).doOnNext(System.out::println);
Mono<Date> m3 = Mono.fromSupplier(Date::new).doOnNext(System.out::println);
m1.subscribe();
m2.subscribe();
m3.subscribe();
Thread.sleep(3000);
m1.subscribe();
m2.subscribe();
m3.subscribe();
}
public static void testFromStream() throws Exception {
Flux<Date> f1 = Flux.fromStream(() -> Stream.of(new Date())).doOnNext(System.out::println);
Flux<Date> f2 = Flux.fromStream(() -> Stream.of(new Date())).doOnNext(System.out::println);
// System.out.println(f1.subscribe());
System.out.println(f1.subscribe());
Thread.sleep(3000);
System.out.println(f2.subscribe());
}
}