在 rest API 逻辑中使用反应时如何避免 Mono#block()
How to avoid Mono#block() when using reactive in rest API logic
所以问题如下:
- 我公开 API 以在我的服务中注册用户
- 在我要注册用户之前,我想在外部服务中验证他(休息API)
- 我想以正确的响应状态通知用户他是否已创建(201 或某些错误代码)
我创建用户的代码如下所示:
@Transactional
public void createUser(UserDto userDto) {
UserEntity newUser = userFactory.createUser(userDto);
String userId = userDto.getUserId();
externalApiService
.validateUser(userId)
.subscribe(a-> userRepository.save(newUser));
}
用户验证如下:
public Mono<Void> validateUser(String userId) {
return webClient
.get(...)
.retrieve()
.toEntity(Void.class);
//Exact request is bit more complicated, but those details shouldn't be crucial in this example
}
我正在使用它的端点看起来像这样:
@PostMapping
public ResponseEntity<Void> createUser(@Valid @RequestBody UserDto dto) {
userService.createUser(dto);
return new ResponseEntity<>(HttpStatus.CREATED);
}
当我使用阻塞 RestTemplate
或对刚从 WebClient
获得的 Mono
使用 block()
时,这非常容易。如果对外部服务的 REST 调用出现异常,我的全局异常处理程序将完成这项工作并使用正确的响应代码响应用户。
但是,如果我想充分利用响应式编程的强大功能而不想 block()
怎么办?我不知道如何正确地做到这一点。谁能给我一些建议?
如果我的问题很简单,请原谅,我对 WebClient
和反应式编程完全陌生。
WebClient
是一个反应式客户端,将它与 non-reactive Spring MVC 一起使用的唯一方法是 block
.
要使流程充分 non-blocking,所有 components/functions 都应该是反应式的。您需要切换到 Spring WebFlux 并使 createUser
反应。
@PostMapping
public Mono<ResponseEntity<Void>> createUser(@RequestBody UserDto dto) {
return userService.createUser(dto)
.map(user -> ResponseEntity.status(HttpStatus.CREATED).build());
}
此代码假定 createUser
是反应性的
public static Mono<UserEntity> createUser(UserDto dto) {
...
}
如果 userRepository
不是反应式的,您可以将 non-reactive 代码和 运行 包装在单独的调度程序 How Do I Wrap a Synchronous, Blocking Call?.
上
所以问题如下:
- 我公开 API 以在我的服务中注册用户
- 在我要注册用户之前,我想在外部服务中验证他(休息API)
- 我想以正确的响应状态通知用户他是否已创建(201 或某些错误代码)
我创建用户的代码如下所示:
@Transactional
public void createUser(UserDto userDto) {
UserEntity newUser = userFactory.createUser(userDto);
String userId = userDto.getUserId();
externalApiService
.validateUser(userId)
.subscribe(a-> userRepository.save(newUser));
}
用户验证如下:
public Mono<Void> validateUser(String userId) {
return webClient
.get(...)
.retrieve()
.toEntity(Void.class);
//Exact request is bit more complicated, but those details shouldn't be crucial in this example
}
我正在使用它的端点看起来像这样:
@PostMapping
public ResponseEntity<Void> createUser(@Valid @RequestBody UserDto dto) {
userService.createUser(dto);
return new ResponseEntity<>(HttpStatus.CREATED);
}
当我使用阻塞 RestTemplate
或对刚从 WebClient
获得的 Mono
使用 block()
时,这非常容易。如果对外部服务的 REST 调用出现异常,我的全局异常处理程序将完成这项工作并使用正确的响应代码响应用户。
但是,如果我想充分利用响应式编程的强大功能而不想 block()
怎么办?我不知道如何正确地做到这一点。谁能给我一些建议?
如果我的问题很简单,请原谅,我对 WebClient
和反应式编程完全陌生。
WebClient
是一个反应式客户端,将它与 non-reactive Spring MVC 一起使用的唯一方法是 block
.
要使流程充分 non-blocking,所有 components/functions 都应该是反应式的。您需要切换到 Spring WebFlux 并使 createUser
反应。
@PostMapping
public Mono<ResponseEntity<Void>> createUser(@RequestBody UserDto dto) {
return userService.createUser(dto)
.map(user -> ResponseEntity.status(HttpStatus.CREATED).build());
}
此代码假定 createUser
是反应性的
public static Mono<UserEntity> createUser(UserDto dto) {
...
}
如果 userRepository
不是反应式的,您可以将 non-reactive 代码和 运行 包装在单独的调度程序 How Do I Wrap a Synchronous, Blocking Call?.