有一个非常相似的问题here,但是答案不足以回答我的问题。
我在@Service
类中有此方法:
@Async
public void activateUser(...){
if(someCondition){
throw new GeneralSecurityException();
}
}
控制器:
@GetMapping( "/activate")
public ResponseEntity<Void> activate(...){
myService.activateUser(...);
}
以及控制器建议:
@RestControllerAdvice( basePackages = "com.app.security" )
public class SecurityAdviceController extends ResponseEntityExceptionHandler {
@ExceptionHandler( GeneralSecurityException.class )
public ResponseEntity<GeneralSecurityExceptionBody> handleGeneralSecurityException( GeneralSecurityException ex ) {
return ResponseEntity
.status( HttpStatus.MOVED_PERMANENTLY )
.header( HttpHeaders.LOCATION, ex.getUrl() )
.body( null );
}
在这里。由于该异常将在另一个线程中引发,我如何继续使其可用于@RestControllerAdvice
?
许多人建议实施AsyncUncaughtExceptionHandler,我同意,但这不能回答问题。
当我删除@Async
时,一切都很好,我可以看到同一线程完成了所有任务,但是使用@Async
时,我有2个线程。
一种解决方案是让父线程抛出异常(但这太麻烦了,我不知道如何实现)。
感谢您的帮助。
答案 0 :(得分:1)
如果您真的想工作异步,那么很可能您使用了错误的工具-最好切换到Spring WebFlux并改用反应式方法。
回到问题,我可以建议2种方法:
@Async
或使用SyncTaskExecutor
,这样任务将
在调用线程中同步执行。@ExceptionHandler(GeneralSecurityException.class)
。相反,请使用CompletableFuture
并提供
exceptionally
处理了逻辑。以下是在控制器和服务中使用CompletableFuture
的示意图:@Controller
public class ApiController {
private final Service service;
public ApiController(Service service) {
this.service = service;
}
@GetMapping( "/activate")
public CompletableFuture<Void> activate(...){
return service.activateUser(...)
.exceptionally(throwable -> ... exception handling goes here ...)
}
}
@Service
public class Service {
@Async
public CompletableFuture<Void> activateUser(...) {
CompletableFuture<Void> future = new CompletableFuture<>();
... your code goes here ...
if(someCondition){
future.completeExceptionally(new GeneralSecurityException());
} else {
future.complete(null);
}
return future;
}
}