单声道switchIfEmpty()总是被调用

我有两种方法。

主要方法:

@PostMapping("/login")

public Mono<ResponseEntity<ApiResponseLogin>> loginUser(@RequestBody final LoginUser loginUser) {

return socialService.verifyAccount(loginUser)

.flatMap(socialAccountIsValid -> {

if (socialAccountIsValid) {

return this.userService.getUserByEmail(loginUser.getEmail())

.switchIfEmpty(insertUser(loginUser))

.flatMap(foundUser -> updateUser(loginUser, foundUser))

.map(savedUser -> {

String jwts = jwt.createJwts(savedUser.get_id(), savedUser.getFirstName(), "user");

return new ResponseEntity<>(HttpStatus.OK);

});

} else {

return Mono.just(new ResponseEntity<>(HttpStatus.UNAUTHORIZED));

}

});

}

以及这个调用的方法(该服务调用了一个外部api):

public Mono<User> getUserByEmail(String email) {

UriComponentsBuilder builder = UriComponentsBuilder

.fromHttpUrl(USER_API_BASE_URI)

.queryParam("email", email);

return this.webClient.get()

.uri(builder.toUriString())

.exchange()

.flatMap(resp -> {

if (Integer.valueOf(404).equals(resp.statusCode().value())) {

return Mono.empty();

} else {

return resp.bodyToMono(User.class);

}

});

}

在上面的示例中,switchIfEmpty()即使Mono.empty()返回了with的结果,也总是从main方法中调用。

我找不到这个简单问题的解决方案。

以下内容也不起作用:

Mono.just(null)

因为该方法将抛出nullpointerexception。

我也不能使用的是flatMap方法来检查是否foundUser为null。

可悲的是,万一我返回,flatMap根本不会被调用Mono.empty(),所以我也不能在这里添加条件。

任何帮助表示赞赏。

@ SimY4

   @PostMapping("/login")

public Mono<ResponseEntity<ApiResponseLogin>> loginUser(@RequestBody final LoginUser loginUser) {

userExists = false;

return socialService.verifyAccount(loginUser)

.flatMap(socialAccountIsValid -> {

if (socialAccountIsValid) {

return this.userService.getUserByEmail(loginUser.getEmail())

.flatMap(foundUser -> {

return updateUser(loginUser, foundUser);

})

.switchIfEmpty(Mono.defer(() -> insertUser(loginUser)))

.map(savedUser -> {

String jwts = jwt.createJwts(savedUser.get_id(), savedUser.getFirstName(), "user");

return new ResponseEntity<>(HttpStatus.OK);

});

} else {

return Mono.just(new ResponseEntity<>(HttpStatus.UNAUTHORIZED));

}

});

}

回答:

这是因为switchIfEmpty接受Mono“按值”。这意味着,即使在您订阅单声道之前,此替代单声道的评估也已触发。

想象这样的方法:

Mono<String> asyncAlternative() {

return Mono.fromFuture(CompletableFuture.supplyAsync(() -> {

System.out.println("Hi there");

return "Alternative";

}));

}

如果您这样定义代码:

Mono<String> result = Mono.just("Some payload").switchIfEmpty(asyncAlternative());

无论在流构建期间发生什么,它总是会触发替代方法。为了解决这个问题,您可以通过使用推迟第二个单声道的评估Mono.defer

Mono<String> result = Mono.just("Some payload")

.switchIfEmpty(Mono.defer(() -> asyncAlternative()));

这样,仅当请求替代项时才打印“ Hi there”

详细说明我的答案。您面临的问题与Reactor无关,而与Java语言本身以及它如何解析方法参数有关。让我们检查一下我提供的第一个示例中的代码。

Mono<String> result = Mono.just("Some payload").switchIfEmpty(asyncAlternative());

我们可以将其重写为:

Mono<String> firstMono = Mono.just("Some payload");

Mono<String> alternativeMono = asyncAlternative();

Mono<String> result = firstMono.switchIfEmpty(alternativeMono);

这两个代码段在语义上是等效的。我们可以继续展开它们,以查看问题所在:

Mono<String> firstMono = Mono.just("Some payload");

CompletableFuture<String> alternativePromise = CompletableFuture.supplyAsync(() -> {

System.out.println("Hi there");

return "Alternative";

}); // future computation already tiggered

Mono<String> alternativeMono = Mono.fromFuture(alternativePromise);

Mono<String> result = firstMono.switchIfEmpty(alternativeMono);

如您所见,当我们开始编写Mono类型时,将来的计算已经触发。为了防止不必要的计算,我们可以将我们的未来纳入延迟评估中:

Mono<String> result = Mono.just("Some payload")

.switchIfEmpty(Mono.defer(() -> asyncAlternative()));

哪个会解开

Mono<String> firstMono = Mono.just("Some payload");

Mono<String> alternativeMono = Mono.defer(() -> Mono.fromFuture(CompletableFuture.supplyAsync(() -> {

System.out.println("Hi there");

return "Alternative";

}))); // future computation defered

Mono<String> result = firstMono.switchIfEmpty(alternativeMono);

在第二个示例中,未来被困在一个懒惰的供应商中,并且仅在需要时才安排执行。

以上是 单声道switchIfEmpty()总是被调用 的全部内容, 来源链接: utcz.com/qa/435455.html

回到顶部