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添加更多的例子。