reactor 3 编程笔记一

【参考资料】
【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 响应式编程
  1. 响应式编程是一种编程范式,基于异步数据流,包含四大主旨:

    响应性:系统能够以一致且可预测的方式及时响应。
    可恢复性:系统能够快速地从故障中恢复。
    弹性:系统能够动态地查找和修复性能瓶颈,不同于可扩展性,弹性系统是根据需求【动态】调整。
    消息驱动:系统依赖于异步消息传递机制,能够确保其松耦合、相互隔离、位置透明和具有容错能力。

  2. 响应式编程从设计角度讲,通常基于观察者模式出现,以数据“推”的方式进行

  3. 响应式编程是lazy的,只有当数据流被订阅才触发,本质是subscriber发出一个request,然后层层上传至publisher

  4. 响应式编程的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个元素进行处理

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值