reactor core官网学习记录

 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());
    }
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值