简体   繁体   English

需要帮助理解反应式 Mono/Flux 类

[英]Need help understanding reactive Mono/Flux classes

I am writing a Java application and attempting to use a Spring WebFlux WebClient to make calls to a REST API.我正在编写一个 Java 应用程序并尝试使用 Spring WebFlux WebClient来调用 REST API。 I just started using this library and have practically no experience with "reactive" programming.我刚开始使用这个库,几乎没有“反应式”编程的经验。 I'm having a hard time understanding how the Mono and Flux classes work and are used.我很难理解MonoFlux类是如何工作和使用的。 What little I understand at this point, these classes allow asynchronous operations with some sort of data source (eg a remote web service).在这一点上我了解的很少,这些类允许对某种数据源(例如远程 Web 服务)进行异步操作。 Everything in WebFlux seems to deal with either a Mono or Flux object. WebFlux 中的一切似乎都处理MonoFlux对象。

My biggest question/confusion at this point is, if they allow for async processing, how do we bridge between the async process and the process that kicked it off?在这一点上,我最大的问题/困惑是,如果它们允许异步处理,我们如何在异步进程和启动它的进程之间架起桥梁? My most recent experience (about 10 years ago) with this type of processing involved Executor s and Future s.我最近(大约 10 年前)对此类处理的经验涉及ExecutorFuture It took me some time to get the hang of those as well.我也花了一些时间来掌握这些。 (I've also forgotten much of it.) (我也忘记了很多。)

Here's some of the code I've written, to try to help illustrate what I'm getting at.这是我编写的一些代码,试图帮助说明我的意思。

@Service
public class GitLabService2 {
  @Autowired
  private WebClient     webClient;
    
  public Flux<String> getGroupByName(String name) {
    Flux<String> result = webClient.get()
      .uri("/groups?search=" + name)
      .accept(MediaType.APPLICATION_JSON)
      .exchangeToFlux(resp -> {
        if (!resp.statusCode().isError()) {
          return resp.bodyToFlux(String.class);
        } else {
          return resp.createException().flatMapMany(Flux::error);
        }
      });
    
    return result;
  }

  public Flux<String> getAllProjectsForGroup(String name) {
    Flux<String> gf = getGroupByName(name);
    int groupID = 0;
    
    gf.subscribe(json -> {
      if (JacksonJsonConverter.isList(json)) {
        List<JsonNode> list = JacksonJsonConverter.convertToObjectList(json);
        // This is the ID of the group I need to use below. However, I can't get it out of this lambda.
        // (Getting info out of lambdas is a separate topic that keeps causing me pain.)
        int groupID = list.get(0).get("id").asInt(); 
      }
    });
    
    Flux<String> result = webClient.get()
      // This is where I need to use the groupID I get above, but can't access it.
      .uri("/groups/" + groupID + "/projects")
      .accept(MediaType.APPLICATION_JSON)
      .exchangeToFlux(resp -> {
        if (!resp.statusCode().isError()) {
          return resp.bodyToFlux(String.class);
        } else {
          return resp.createException().flatMapMany(Flux::error);
        }
      });
    
    return result;
  }
    
}

Here is code that uses the code above.这是使用上述代码的代码。

  private void getAllProjectsForGroup() {
    Flux<String> result = service.getAllProjectsForGroup("test");

    result.subscribe(jsonStr -> {
      // Do things with the JSON data ...
    });
  }

I'm not seeing the asynchronicity in these mechanisms.我没有看到这些机制中的异步性。 Won't this still block while waiting for the Mono or Flux object to "do its thing"?在等待MonoFlux对象“做它的事情”时,这不会阻塞吗? Wouldn't I need to involve a thread or executor or some similar mechanism?我不需要涉及线程或执行程序或一些类似的机制吗? I don't understand how this works, or how to properly use it.我不明白这是如何工作的,或者如何正确使用它。

I would think that "subscribing" to the Mono or Flux means that I may receive a response at some future time (granted, it could be just a few milliseconds).我认为“订阅” MonoFlux意味着我可能会在未来某个时间收到响应(当然,它可能只是几毫秒)。 Does that mean that the subscribe() call does not block?这是否意味着subscribe()调用不会阻塞?

I've searched and read from a lot of what I've found, but it's still not clear to me.我已经搜索并阅读了很多我发现的东西,但我仍然不清楚。 It seems like there is a critical piece of information that's missing.似乎缺少一条关键信息。

I think I'm also having a hard time understanding how to properly deal with the situation (like in the service getAllProjectsForGroup() method above) where I get a piece of information within a lambda expression (I think anonymous classes also suffer from this issue) and need to use it "outside".我想我也很难理解如何正确处理这种情况(比如上面的服务getAllProjectsForGroup()方法),我在 lambda 表达式中获取了一条信息(我认为匿名类也遇到了这个问题) 并且需要在“外部”使用它。 Perhaps this needs to be asked as a separate topic.也许这需要作为一个单独的主题提出。

Basically reactive/future like objects such as these, including standard java objects like CompletableFuture, force you to use them in the entire chain from controller to service.基本上像这样的反应/未来对象,包括像 CompletableFuture 这样的标准 java 对象,迫使您在从控制器到服务的整个链中使用它们。 They are a task running in some other thread.它们是在其他线程中运行的任务。 So your controller returns a Mono, and calls your service which returns a mono... and you get it.所以你的控制器返回一个单声道,并调用你的服务返回一个单声道......你就明白了。 Each task completion starts the next.每个任务完成都会开始下一个。

So you have two options afaik, either refactor getAllProjectsForGroup to return a Mono/Flux too, or use a blocking operation (big no for me), such as Mono.block(), to convert it to synchronous code, but wasting a thread, and basically make reactive code pointless因此,您有两个选项 afaik,要么重构 getAllProjectsForGroup 以也返回 Mono/Flux,要么使用阻塞操作(对我来说大不),例如 Mono.block(),将其转换为同步代码,但浪费线程,并且基本上使反应式代码毫无意义

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

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