简体   繁体   English

我们如何迭代和打印来自 Reactor Flux 或 Mono FlatMap 或 FlatMapMany 的值?

[英]How can we iterate and print the values from Reactor Flux or Mono FlatMap or FlatMapMany?

Learning Reactor with Spring Boot.使用 Spring Boot 学习 Reactor。

Using a sample API:使用示例 API:

https://jsonplaceholder.typicode.com/todos/1
{
  "userId": 1,
  "id": 1,
  "title": "delectus aut autem",
  "completed": false
}

Wanted to map the above to an object (defined a pojo SingleUser ) and print the output.想要将上面的映射到一个对象(定义一个 pojo SingleUser )并打印输出。

private WebClient webClient = WebClient.create("https://jsonplaceholder.typicode.com");

private Mono<ClientResponse> responseMono = webClient.get()
          .uri("/todos/1")
          .accept(MediaType.APPLICATION_JSON)
          .exchange();

public String getResult() {
   return ">> result = " + responseMono.flatMap(res -> res.bodyToMono(String.class)).block();
}

When using the above.. the result is:使用上述内容时..结果是:

>> result = {
  "userId": 1,
  "id": 1,
  "title": "delectus aut autem",
  "completed": false
}

How can i iterate and print all values when using Flux as below?使用 Flux 时如何迭代和打印所有值,如下所示?

public Flux<SingleUser> listUsers1() {
    return webClient.get()
             .uri("/todos/1")
             .retrieve()
             .bodyToFlux(SingleUser.class);
}

public String getUsers1() {
   return ">> Get Users 1= " + listUsers1();
}

public Flux<SingleUser> listUsers2() {
   return webClient.get()
             .uri("/todos/1")
             .exchange()
             .flatMapMany(clientResponse -> clientResponse.bodyToFlux(SingleUser.class));
}

public String getUsers2() {
   return ">> Get Users 2= " + listUsers2();
}

Result when using both exchange() and retrieve() :使用exchange()retrieve()

>> Get Users 1= MonoFlatMapMany
>> Get Users 2= MonoFlatMapMany

How can we iterate through the object and print the values?我们如何遍历对象并打印值?

First please note that you are dealing with an asynchronous non-blocking model, but you are basically resorting to blocking for demonstration purposes.首先请注意,您正在处理异步非阻塞模型,但您基本上是为了演示目的而诉诸阻塞。

The limit of that switch from async to sync shows when dealing with multiple values, because while each of these Flux can be printed out, you won't be in control of the "iteration" (which can happen in an interleaved manner between the 2 requests):当处理多个值时,从异步切换到同步的限制显示,因为虽然这些Flux每一个都可以打印出来,但您将无法控制“迭代”(这可能以交错的方式发生在 2要求):

There is a family of Reactor operators called "side effects" for when you want to peek at the values in a sequence to eg.当您想查看序列中的值时,有一组称为“副作用”的 Reactor 运算符。 log/print them: doOn* .记录/打印它们: doOn* You can use doOnNext to print each value emitted by a Flux :您可以使用doOnNext打印Flux发出的每个值:

listUsers1().doOnNext(u -> System.out.println("listUsers1 received " + u);
listUsers2().doOnNext(u -> System.out.println("listUsers2 received " + u);

Only trouble is that this doesn't subscribe to the respective printing Flux , so nothing will happen.唯一的问题是这不会订阅相应的打印Flux ,所以什么都不会发生。 Even if you just .subscribe() in your test, the app could exit immediately without waiting for the end of these two async sequences.即使您只是在测试中使用.subscribe() ,应用程序也可以立即退出,而无需等待这两个异步序列的结束。

So like in your first example, you need to block.所以就像在你的第一个例子中一样,你需要阻止。 With Flux , you can use .blockLast() to block until the flux completes.使用Flux ,您可以使用.blockLast()进行阻塞,直到通量完成。

Second trouble: your getUsersX() methods expect to be able to retrieve a String and return it, synchronously.第二个麻烦:您的getUsersX()方法希望能够同步检索String并返回它。 This is not going to be practical with a Flux even with blockLast from above:即使使用上面的 blockLast,这对于Flux也不实用:

public String getUsers1() {
       return ">> Get Users 1= " + listUsers1().doOnNext(System.out::println).blockLast();
    }

public String getUsers2() {
   return ">> Get Users 2= " + listUsers2().doOnNext(System.out::println).blockLast();
}

System.out.println(getUsers1());
System.out.println(getUsers2());

Would log something like:会记录如下内容:

user1A
user1B
user1C
user1D
>> Get Users 1= user1D
user2A
user2B
user2C
>> Get Users 2= user2C

Notice how each request prints all values THEN the Get Users message with the last value repeated.请注意每个请求如何打印所有值然后重复最后一个值的 Get Users 消息。 Also, due to the blockLast() the first request must run its course before the second request is triggered.此外,由于blockLast() ,第一个请求必须在触发第二个请求之前运行。

The most reactive way of printing the request, with support for parallel requests, is to asynchronously collect the users and print the list once it becomes available:打印请求的最被动方式(支持并行请求)是异步收集用户并在列表可用时打印:

listUsers1().collectList().doOnNext(l1 -> System.out.println(">> Get Users 1=" + l1).subscribe();
listUsers2().collectList().doOnNext(l2 -> System.out.println(">> Get Users 2=" + l2).subscribe();

But that suffers from the same caveat of not blocking in a main/test: the app could terminate before the lists are emitted so nothing gets printed.但这也有相同的警告,即在主/测试中不阻塞:应用程序可能会在列表发出之前终止,因此不会打印任何内容。 We can tie the two collectList into a Mono and wait for both completions using Mono.when :我们可以将两个 collectList 绑定到 Mono 并使用Mono.when等待两个完成:

Mono.when(
    listUsers1().collectList().doOnNext(l1 -> System.out.println(">> Get Users 1=" + l1),
    listUsers2().collectList().doOnNext(l2 -> System.out.println(">> Get Users 2=" + l2)
)
.block();

With that code, both requests are triggered at the same time and the fastest to complete is printed first, whichever that is.使用该代码,同时触发两个请求,并首先打印最快完成的请求,无论哪个。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM