Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/398.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 在SpringMVC应用程序中混合JPA和反应式代码_Java_Spring_Spring Boot_Spring Mvc_Spring Webflux - Fatal编程技术网

Java 在SpringMVC应用程序中混合JPA和反应式代码

Java 在SpringMVC应用程序中混合JPA和反应式代码,java,spring,spring-boot,spring-mvc,spring-webflux,Java,Spring,Spring Boot,Spring Mvc,Spring Webflux,我有一个SpringMVC(不是WebFlux)应用程序,它使用WebFlux项目中的WebClient类。除了与WebClient相关的代码外,应用程序中的所有现有代码都是基于CompletableFutures的异步代码,对JPA的阻止调用通常是这样完成的: @Service public class MyService { private final MyRepository repo; private final Executor executor; // configured

我有一个SpringMVC(不是WebFlux)应用程序,它使用WebFlux项目中的
WebClient
类。除了与
WebClient
相关的代码外,应用程序中的所有现有代码都是基于
CompletableFuture
s的异步代码,对JPA的阻止调用通常是这样完成的:

@Service
public class MyService {
  private final MyRepository repo;
  private final Executor executor;  // configured by me & injected by Spring

  ...

  @Async
  public CompletableFuture<MyResult> doSomething() {
    return CompletableFuture
        .supplyAsync(() => repo.findById(...), executor)
        .thenApply(...);
  }
}
我知道1是急切的,而2是被动的,但我不明白的是:

  • Mono.fromRunnable
    不接受执行器。它是否在自己的调度程序线程上运行
    Runnable
  • 我听说在Spring MVC应用程序中使用反应式
    WebClient
    ,也会带来性能优势。但是在我的例子中,我已经在整个MVC应用程序中使用了我自己的执行器,使用
    Mono.fromRunnable
    而不是我自己的执行器是否不好

(我找到了描述如何使用publishOn进行阻塞调用的,但我认为这是针对我有一个反应式WebFlux应用程序的场景。在MVC应用程序的情况下,我找不到任何相关文档。)

WebClient
的工作线程非常有限,您不应该在这些线程上执行阻塞操作(选项2),我假设你不想使用选项1,它不容易阅读,也不是很必要。就你而言,你可以这样做

fetchFooUsingWebClient()
.publishOn(Schedulers.boundedElastic())
.map(foo -> saveFooBlocking(foo))
//.bla - other operators, eg. doOnNext, doOnError, etc
.subscribe() // or .block() if you want to get the result, note, this will blcok the caller thread (which calls fetchFooUsingWebClient)

事实上,我对选项1很满意,只要它是有效的。我觉得最好能为运行一切的MVC应用程序提供一个中央
任务调度器
,而不是不必要地引入一个反应式
调度器
。尽管它很难看,你知道选项1是否有效吗?如果可能的话,我建议你使用反应堆结构,因为你已经在使用它了。您需要注意的一点是
CompletableFuture。SupplySync
使用commons池,默认情况下只有很少的线程。使用它可能不是一个好主意,因为它可能是一个瓶颈(db调用等待执行的线程)。对我来说,带一个定制的
TaskManager
似乎有点过头了,正确使用它也不是那么容易。除非必要,否则我建议依赖您已经使用的抽象,而不是创建自己的抽象。
TaskManager
是一个拼写错误,我是指Spring
TaskExecutor
。我为我的Spring MVC应用程序配置了一个线程池任务执行器,我通过
CompletableFuture.supplyAsync(…,executor)
在特定的线程池任务执行器上运行所有的
CompletableFuture
如果可能的话,我建议您使用reactor构造,因为您已经在使用它了我主要担心的是,MVC应用程序的其余部分没有使用reactor结构,所以我不知道从reactive世界引入
调度器是否有好处。正如我所说,您已经在使用它了。如果你真的不想这样,你应该有一个类,比如说
SomeHttpClient
,它返回POJO,而不是反应性构造,那么你可以只进行db调用,也不需要在另一个线程中运行db调用,只需在servlet中运行包含工作线程的类。当然,我没有您设置的完整上下文,所以这只是我的观点。如果您在非反应式应用程序中使用
block
,webclient的行为将与
restemplate
@thomas完全相同,实际上并非如此。1) ,这取决于http客户端的使用情况,考虑到线程池、IO模型,可能会有很大的不同。2) API非常不同,因此您的编程方式也非常不同。
fetchFooUsingWebClient()
.publishOn(Schedulers.boundedElastic())
.map(foo -> saveFooBlocking(foo))
//.bla - other operators, eg. doOnNext, doOnError, etc
.subscribe() // or .block() if you want to get the result, note, this will blcok the caller thread (which calls fetchFooUsingWebClient)