如何在不使用阻塞的情况下将Mono转换为Recipe?

huangapple go评论109阅读模式
英文:

How to convert Mono<Recipe> to Recipe without using block?

问题

我刚接触WebFlux我在不使用block的情况下将Mono转换为我的Recipe方面遇到了一些困难我尝试过使用flatMap和subscribe但是无法使其工作

@Override
public Mono<Void> deleteById(String recipeId, String idToDelete) {

    log.debug("正在删除食谱:" + recipeId + ":" + idToDelete);

    Recipe recipe = recipeReactiveRepository.findById(recipeId).block();

    if(recipe != null){
        log.debug("找到食谱");

        Optional<Ingredient> ingredientOptional = recipe
                .getIngredients()
                .stream()
                .filter(ingredient -> ingredient.getId().equals(idToDelete))
                .findFirst();

        if(ingredientOptional.isPresent()){
            log.debug("找到配料");
            Ingredient ingredientToDelete = ingredientOptional.get();
            recipe.getIngredients().remove(ingredientOptional.get());
            recipeReactiveRepository.save(recipe);
        }
    } else {
        log.debug("未找到食谱ID。ID:" + recipeId);
    }
    return Mono.empty();
}
英文:

I am new to webflux and I am having a tough time converting the Mono to my Recipe without using block. I tried using flatmap and subscribe, but i couldn't get it to work.

@Override
    public Mono&lt;Void&gt; deleteById(String recipeId, String idToDelete) {

        log.debug(&quot;Deleting ingredient: &quot; + recipeId + &quot;:&quot; + idToDelete);

        Recipe recipe = recipeReactiveRepository.findById(recipeId).block();

        if(recipe != null){
            log.debug(&quot;found recipe&quot;);

            Optional&lt;Ingredient&gt; ingredientOptional = recipe
                    .getIngredients()
                    .stream()
                    .filter(ingredient -&gt; ingredient.getId().equals(idToDelete))
                    .findFirst();

            if(ingredientOptional.isPresent()){
                log.debug(&quot;found Ingredient&quot;);
                Ingredient ingredientToDelete = ingredientOptional.get();
                recipe.getIngredients().remove(ingredientOptional.get());
                recipeReactiveRepository.save(recipe);
            }
        } else {
            log.debug(&quot;Recipe Id Not found. Id:&quot; + recipeId);
        }
        return Mono.empty();
    }

答案1

得分: 0

你应该深入了解一下响应式编程的基础知识,仅仅在底部添加一个 Mono.empty() 是不会使其变为响应式的。响应式意味着你要让反应器建立起一系列的函数链,这样系统在需要时才能自己切换线程,以确保没有闲置。

在响应式应用中,你绝不应该进行阻塞操作。这会降低应用程序的性能,可能导致非常糟糕的表现。

所以下面这样的操作是不允许的,也不应该这样做。

Recipe recipe = recipeReactiveRepository.findById(recipeId).block();

那么应该如何处理呢?你应该声明一个在返回的 Producer(Mono 或 Flux)上执行的函数链。

这里是一个示例,展示了如何进行操作:

return recipeReactiveRepository.findById(recipeId).flatMap(recipe -> {
    // 在这里执行逻辑,然后返回一个 Flux/Mono

};

你正在试图使用响应式库编写命令式的代码。例如,Producers(monos 和 fluxes)中不允许使用 null,因此在大多数情况下进行空值检查是多余的。

此外,响应式编程主要使用 纯函数,因此无返回值的函数或者没有在返回语句上进行链接的函数会破坏你的代码。

// 这里你只是忽略了保存的返回值,这会中断响应式链并且不会被执行。
recipeReactiveRepository.save(recipe);

所以你总是需要注意你的返回值。另一方面,如果你想要忽略返回值并返回空,你可以使用 then 操作符。

举个例子:

return recipeReactiveRepository.findById(recipeId).flatMap(recipe -> {

    // 在这里进行操作,然后保存并返回

    return recipeReactiveRepository.save(updatedRecipe);

// Mono#then 确保 recipeReactiveRepository#save 的返回值被丢弃,而会返回一个空的 Mono#empty

}.then();

如果你想学习响应式编程,我强烈建议你阅读 Reactor 文档中的 "入门" 部分。

Reactor 入门

这样你就能理解基本概念,以及它与普通的 "标准" 编程的区别。

英文:

you should read up on the basics of reactive programming, just adding a Mono.empty() at the bottom doesnt make it reactive. Reactive means that you let the reactor establish a reactive chain of functions, so that the system, can itself switch threads when it needs to so that nothing is idleing.

You should never block in a reactive application. This will slow down your application and you could potentially end up with very bad performance.

So this is not allowed and should not be done.

Recipe recipe = recipeReactiveRepository.findById(recipeId).block();

So how should you do it, well you should declare a chain of functions to be performed on the returned Producer (Mono or Flux)

Here is one example of how it could be done.

return recipeReactiveRepository.findById(recipeId).flatMap(recepie -&gt; {
    // here you will do your logic and return a Flux/Mono of something.
};

You are trying to write imperative code using a reactive library. For example, null is not allowed in Producers (monos and fluxes), so doing null checks is redundant is most cases.

Also reactive programming uses mostly pure functions so void functions or not chaining on return statements will break your code.

// Here you are just ignoring the return from the save, this will break the reactive chain and not be executed.
recipeReactiveRepository.save(recipe);

So you will always have to take care of you returns. On the other hand if you want to say ignore the return and return empty you can use the then operator.

So for example:

return recipeReactiveRepository.findById(recipeId).flatMap(recipe -&gt; {

    // do things here then save and return

    return recipeReactiveRepository.save(updatedRecipe);

// Mono#then will make sure the return from recipeReactiveRepository#save
// is dropped, and will return a Mono#empty instead

}.then();   


If you want to learn reactive programming i highly encourage you to read the "getting started" section in the Reactor documentation.

Reactor Getting Started

So you understand the basic concepts, how it is written, because it is different from regular "standard" programming.

huangapple
  • 本文由 发表于 2020年8月22日 21:24:01
  • 转载请务必保留本文链接:https://go.coder-hub.com/63536668.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定