Reactor速成手册

Reactor is a fully non-blocking reactive programming foundation for the JVM, with efficient demand management (in the form of managing “backpressure”).

听上去很难,但是它也遵循帕累托法则。 也就是说只要掌握它20%的功能,就能完成大部分的日常工作。

以我现在的项目为例,到目前为止我们还没用过backpressure 。我们经常使用的功能是

  • (Flux|Mono).just
  • (Flux|Mono).map
  • (Flux|Mono).flatMap
  • (Flux|Mono).onErrorResume
  • (Flux|Mono).filter

这都是一些最简单的功能,但也是最常用的功能。所以不用担心,读过这篇博客后我相信你也可以在自己的项目里轻松地使用它。

如何安装?

添加下面的配置到你的 pom.xml。我们在这里使用 BOM,这样就不用担心版本兼容的问题了。

<dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>io.projectreactor</groupId>
            <artifactId>reactor-bom</artifactId>
            <version>2020.0.16</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
    </dependencies>
</dependencyManagement>
<dependencies>
    <dependency>
        <groupId>io.projectreactor</groupId>
        <artifactId>reactor-core</artifactId>
    </dependency>
    <dependency>
        <groupId>io.projectreactor</groupId>
        <artifactId>reactor-test</artifactId>
        <scope>test</scope>
    </dependency>
</dependencies>
复制代码

如何测试?

Reactor提供了一个测试库,我们可以使用库中的 StepVerifier 来做下面的事情

  • 验证元素及其顺序

    StepVerifier.create(Flux.fromArray(new Integer[] {1, 2, 3, 4, 5})).expectNext(1)
        .expectNext(2).expectNext(3).expectNext(4).expectNext(5).verifyComplete();
    复制代码
  • 验证错误

    StepVerifier.create(Flux.error(new Exception("some error")))
            .verifyErrorMessage("some error");
    复制代码
  • 验证序列是否结束

    StepVerifier.create(Flux.empty()).verifyComplete();
    复制代码

在下面的章节里,我们会使用 StepVerifier 来验证代码。

有哪些基本概念?

Reactor有两个最基本的概念

  • Flux

    表示一列数据,数据个数可能是0个,也可能是任意多个。

  • Mono

    表示一列数据,数据个数要么是0个,要么是1个。

最常用的那20%功能是什么?

在这一节,我会使用几个概念来对功能进行分组

  • 装箱

    将数据放入 Flux|Mono

  • 转换

    将当前数据转换为另外的数据

  • 检视

    查看元素的值并执行一些操纵,但不会改变元素的值

  • 拆箱

    从 Flux|Mono中取出数据

装箱

如何处理String?

  • Flux

    @Test
    public void canBeCreatedFromString() {
        StepVerifier.create(Flux.just("hello world")).expectNext("hello world").verifyComplete();
    }
    复制代码
  • Mono

    @Test
    public void canBeCreatedFromString() {
        StepVerifier.create(Mono.just("hello world")).expectNext("hello world").verifyComplete();
    }
    复制代码

如何处理Number?

  • Flux

    @Test
    public void canBeCreatedFromNumber() {
        StepVerifier.create(Flux.just(1)).expectNext(1).verifyComplete();
        StepVerifier.create(Flux.just(1.0)).expectNext(1.0).verifyComplete();
    }
    复制代码
  • Mono

    @Test
    public void canBeCreatedFromNumber() {
        StepVerifier.create(Mono.just(1)).expectNext(1).verifyComplete();
        StepVerifier.create(Mono.just(1.0)).expectNext(1.0).verifyComplete();
    }
    复制代码

如何处理 Optional 或者 Nullable 的数据?

只有Mono可以执行这个操作

@Test
public void canBeCreatedFromNullableValue() {
    String value = null;
    StepVerifier.create(Mono.justOrEmpty(value)).verifyComplete();

    value = "hello world";
    StepVerifier.create(Mono.justOrEmpty(value)).expectNext("hello world").verifyComplete();
}

@Test
public void canBeCreatedFromOptionalValue() {

    Optional<String> value = Optional.empty();
    StepVerifier.create(Mono.justOrEmpty(value)).verifyComplete();

    value = Optional.of("hello world");
    StepVerifier.create(Mono.justOrEmpty(value)).expectNext("hello world").verifyComplete();
}
复制代码

如何处理一个数据生成器?

这里数据生成器是指没有参数的函数,它的函数签名是() -> A。

只有Mono可以执行这个操作。

@Test
public void canBeCreatedFromCallable() {
    StepVerifier.create(Mono.fromCallable(() -> "hello world!")).expectNext("hello world!")
            .verifyComplete();
}
复制代码

如何处理Array?

只有Flux可以执行这个操作。

@Test
public void canBeCreatedFromArray() {
    StepVerifier.create(Flux.fromArray(new Integer[] {1, 2, 3, 4, 5})).expectNext(1)
            .expectNext(2).expectNext(3).expectNext(4).expectNext(5).verifyComplete();
}
复制代码

如何处理Iterable?

只有Flux可以执行这个操作。

@Test
public void canBeCreatedFromList() {
    List<Integer> list = new LinkedList<Integer>();
    list.add(1);
    list.add(2);
    list.add(3);
    list.add(4);

    StepVerifier.create(Flux.fromIterable(list)).expectNext(1).expectNext(2).expectNext(3)
            .expectNext(4).verifyComplete();
}

@Test
public void canBeCreatedFromSet() {
    Set<Integer> set = new HashSet<Integer>();
    set.add(1);
    set.add(2);
    set.add(2);
    set.add(3);
    set.add(4);

    StepVerifier.create(Flux.fromIterable(set)).expectNext(1).expectNext(2).expectNext(3)
            .expectNext(4).verifyComplete();
}
复制代码

如何处理Stream?

只有Flux可以执行这个操作。

@Test
public void canBeCreatedFromStream() {
    Stream<Integer> stream = Stream.of(1, 2, 3, 4, 5);
    StepVerifier.create(Flux.fromStream(stream)).expectNext(1).expectNext(2).expectNext(3)
            .expectNext(4).expectNext(5).verifyComplete();
}
复制代码

如何处理Throwable?

  • Flux

    @Test
    public void canBeCreatedFromThrowable() {
        StepVerifier.create(Flux.error(new Exception("some error")))
                .verifyErrorMessage("some error");
    }
    复制代码
  • Mono

    @Test
    public void canBeCreatedFromThrowable() {
        StepVerifier.create(Mono.error(new Exception("some error")))
                .verifyErrorMessage("some error");
    }
    复制代码

转换

如何对元素进行过滤?

  • Flux

    @Test
    public void canDoFilter() {
        Flux<Integer> flux = Flux.just(1, 2, 3, 4, 5, 6);
        StepVerifier.create(flux.filter(x -> x > 5)).expectNext(6).verifyComplete();
    }
    复制代码
  • Mono

    @Test
    public void canDoFilter() {
        StepVerifier.create(Mono.just(6).filter(x -> x > 5)).expectNext(6).verifyComplete();
        StepVerifier.create(Mono.just(2).filter(x -> x > 5)).verifyComplete();
    }
    复制代码

如何在每个元素上执行函数A -> B?

假设有一个函数A -> B,其中A是Flux|Mono的元素类型, B又不是 Flux|Mono,那么我们可以使用 (Flux|Mono).map 来在每个元素上执行这个函数。

  • Flux

    @Test
    public void canMapTheTypeOfValueInSequenceToAnotherType() {
        StepVerifier.create(flux.map(x -> x.toString())).expectNext("1").expectNext("2")
                .expectNext("3").expectNext("4").expectNext("5").expectNext("6").verifyComplete();
    }
    
    @Test
    public void canMapTheValueInSequenceToAnotherValue() {
        StepVerifier.create(flux.map(x -> x + 1)).expectNext(2).expectNext(3).expectNext(4)
                .expectNext(5).expectNext(6).expectNext(7).verifyComplete();
    }
    复制代码
  • Mono

    @Test
    public void canMapTheTypeOfValueInSequenceToAnotherType() {
        StepVerifier.create(Mono.just(1).map(x -> x.toString())).expectNext("1").verifyComplete();
    }
    
    @Test
    public void canMapTheValueInSequenceToAnotherValue() {
        StepVerifier.create(Mono.just(1).map(x -> x + 1)).expectNext(2).verifyComplete();
    }
    复制代码

如何在每个元素上执行函数A -> (Flux|Mono)<B>?

假设有一个函数A -> (Flux|Mono)<B>,其中A是Flux|Mono的元素类型,那么我们可以使用 (Flux|Mono).flatMap 或者 Mono.flatMapMany 来在每个元素上执行这个函数。

  • Flux

    @Test
    public void canMapTheValueInSequenceToAnotherSequence() {
    
        StepVerifier.create(flux.flatMap(x -> Flux.just(x, x))).expectNext(1).expectNext(1)
                .expectNext(2).expectNext(2).expectNext(3).expectNext(3).expectNext(4).expectNext(4)
                .expectNext(5).expectNext(5).expectNext(6).expectNext(6).verifyComplete();
    
        StepVerifier.create(flux.flatMap(x -> Mono.just(x))).expectNext(1).expectNext(2)
                .expectNext(3).expectNext(4).expectNext(5).expectNext(6).verifyComplete();
    }
    复制代码
  • Mono

    @Test
    public void canMapTheValueInSequenceToAnotherSequence() {
    
        StepVerifier.create(Mono.just(1).flatMapMany(x -> Flux.just(x, x))).expectNext(1)
                .expectNext(1).verifyComplete();
    
        StepVerifier.create(Mono.just(1).flatMap(x -> Mono.just(x + 1))).expectNext(2)
                .verifyComplete();
    }
    复制代码

如何在没有数据的时候给一个默认值?

  • Flux

    @Test
    public void canRecoverWithSingleDefaultValueFromEmptySequence() {
        StepVerifier.<Integer>create(Flux.<Integer>empty().defaultIfEmpty(1)).expectNext(1)
                .verifyComplete();
    }
    复制代码
  • Mono

    @Test
    public void canRecoverWithSingleDefaultValueFromEmptySequence() {
        StepVerifier.<Integer>create(Mono.<Integer>empty().defaultIfEmpty(1)).expectNext(1)
                .verifyComplete();
    }
    复制代码

如何在没有数据的时候将现在Flux|Mono替换为另一个Flux|Mono?

  • Flux

    @Test
    public void canRecoverWithAnotherSequenceFromEmptySequence() {
        StepVerifier.<Integer>create(Flux.<Integer>empty().switchIfEmpty(Flux.just(1)))
                .expectNext(1).verifyComplete();
    }
    复制代码
  • Mono

    @Test
    public void canRecoverWithAnotherSequenceFromEmptySequence() {
        StepVerifier.<Integer>create(Mono.<Integer>empty().switchIfEmpty(Mono.just(1)))
                .expectNext(1).verifyComplete();
    }
    复制代码

检视

如何打印每一个元素?

我们可以使用(Flux|Mono).doOnNext 来查看每个元素的值并做一些操作,但不会改变元素的值。

  • Flux

    @Test
    public void canDoSomethingForEveryElement() {
        Flux<Integer> flux = Flux.just(1, 2, 3, 4, 5, 6);
        flux.doOnNext(x -> System.out.println(x)).collectList().block();
    }
    复制代码
  • Mono

    @Test
    public void canDoSomethingForEveryElement() {
        Mono.just(1).doOnNext(x -> System.out.println(x)).block();
    }
    复制代码

拆箱

如何将Flux转换为一个List?

@Test
public void canBeConvertedToList() {
    List<Integer> list = Flux.just(1, 2, 3).collectList().block();
    assertThat(list.size()).isEqualTo(3);
    assertThat(list.get(0)).isEqualTo(1);
    assertThat(list.get(1)).isEqualTo(2);
    assertThat(list.get(2)).isEqualTo(3);
}
复制代码

如何从Mono中取出数据?

@Test
public void canBeConvertedToValue() {
    assertThat(Mono.just(1).block()).isEqualTo(1);
    assertThat(Mono.empty().block()).isNull();
}
复制代码

总结

我创建了一个repo reactor-examples,里面包含了上面所有的例子。

下载这个repo自己尝试一下吧!

git clone [email protected]:sjmyuan/reactor-examples.git
复制代码

欢迎提交PR添加更多的例子。

Guess you like

Origin juejin.im/post/7067182919076282376