在 Spring 网络控制器中使用 Mono<T>

Consuming a Mono<T> in a Spring web Controller

我目前正在尝试了解 Reactor 并重构了一个返回 Optional<CompanyDetails> 的服务方法以使用 Reactor 的 Mono<CompanyDetails> 代替:

public Mono<CompanyDetails> findOne(String id) {
    CompanyDetails result = retrieveFromSomewhere(id);
    return Mono.justOrEmpty(result);
}

根据我的理解,这应该发出 empty()just(result)。 我在这样的 Spring 网络控制器中使用服务:

@RequestMapping(value = "{id}", method = RequestMethod.GET)
public DeferredResult<CompanyDetails> getCompany(@PathVariable String id) {
    final DeferredResult<CompanyDetails> result = new DeferredResult<>();
    companyService.findOne(id)
            .consume(result::setResult);
    return result;
}

如果找到结果,这工作正常,但如果 findOne 发出 empty(),它就会超时。我可以显式调用 get() 并检查 null,但感觉完全错误。

另外:在重构之前,getCompany 如果没有找到结果则抛出一个 NotFoundException,这是否可能,或者我完全走错了路?

自己找到了答案:首先发现 Reactor 的 Mono 有一个 toCompletableFuture 方法,Spring MVC 也可以使用它来代替 DeferredResult。失败 CompletableFuture 将按预期抛出异常。

要失败,Mono 必须发出 error 而不是 empty:

public Mono<CompanyDetails> findOne(String id) {
    CompanyDetails result = retrieveFromSomewhere(id);
    return Mono
            .justOrEmpty(result)
            .otherwiseIfEmpty(Mono.error(...));
}

@RequestMapping(value = "{id}", method = RequestMethod.GET)
public CompletableFuture<CompanyDetails> getCompany(@PathVariable String id) {
    return companyService.findOne(id)
            .toCompletableFuture();
}

现在好多了。