在我的应用程序中,我有3个将来的调用,这些调用是并行进行的,并且当收到其中一个的响应时,我还有另外3个请求,所有这些请求都应在继续执行代码之前完成,恰好是spring中的DeferredResult
。
过了一会儿,我意识到页面有时是在后三个请求完成之前呈现的。原始源代码(为简单起见,省略了逻辑):
public DeferredResult<String> someControllerMethod() {
DeferredResult<String> result = new DeferredResult();
CompletableFuture.allOf(
future1(),
future2(),
future3()
)
.whenComplete((aVoid, throwable) -> result.setResult("something"));
return result;
}
public CompletableFuture<?> future3() {
return someService.asyncCall()
.thenApplyAsync(response -> {
....
return CompletableFuture.allOf(
future4(),
future5(),
future6()
);
}
);
}
使用
thenApplyAsync
有时DeferredResult
在实际的未来之前完成,而更改为thenComposeAsync
似乎可以解决问题。有人可以解释一下为什么吗?还是这是我的代码中的某个错误,并且不应以这种方式运行? 最佳答案
thenApply[Async]
接受评估为任意值的函数。返回值后,将来将使用该值来完成。当函数(如您的代码中)返回另一个future时,这并没有增加其他含义,future将是结果值(无论是否完成),就像其他任何对象一样。
实际上,您的
public CompletableFuture<Void> future3() {
return someService.asyncCall()
.thenApplyAsync(response -> {
....
return CompletableFuture.allOf(
future4(),
future5(),
future6()
);
}
);
}
方法甚至不编译,因为结果为
CompletableFuture<CompletableFuture<Void>>
,其结果值为另一个未来的未来。不发现错误的唯一方法是使用更广泛的类型,例如CompletableFuture<Object>
或CompletableFuture<?>
,作为future3()
的返回类型。相反,
thenCompose[Async]
期望一个函数可以对另一个未来进行评估,以精确地达到您期望的结果。这是“应用”和“撰写”之间的根本区别。如果您保留CompletableFuture<Void>
的特定future3()
返回类型,则编译器已经指导您使用“ compose”,因为只有这种接受。public CompletableFuture<Void> future3() {
return someService.asyncCall()
.thenComposeAsync(response -> {
....
return CompletableFuture.allOf(
future4(),
future5(),
future6()
);
}
);
}