9D5.异步及异常处理
原创2024/5/8实战手册异步大约 2 分钟
9D5.异步及异常处理
实践中,我们主张同步优先,能同步的尽量同步。使用异步处理时,遵循以下实践。
- 异步方法 - 命名和签名
- 异常处理 - 不应该吞掉异常
- 线程池 - 线程池分配
9D5.1.Async注解
使用@Async注解的方法,会在taskExecutor线程池中执行,默认前缀为exec-,
- 方法名,建议使用
Async后缀,如orderAsync - 返回值,使用
Future,如CompletableFuture
如下代码,不建议使用void方法,而以Future<Void>和.complete(null)替代, 他们的主要区别在于未捕获异常的处理,void会吃掉异常,不能传递给调用者。
@Async
public void badAsync() {
// exception handled by AsyncConfigurer#getAsyncUncaughtExceptionHandler
}
@Async
public CompletableFuture<Void> goodAsync() {
// exception handled by caller via AOP/ExceptionHandler
return CompletableFuture.completedFuture(null);
}9D5.2.异步请求
SpringMvc的RequestMapping方法不可使用@Async,通过返回值完成异步处理。
Future- 组合使用异步ServiceCallable- 组合同步service,使用applicationTaskExecutor线程池,默认前缀app-exec-DeferredResult- 相当于Context传入,不建议使用
在SpringBoot3.2中,线程池和异常的处理过程如下,其中,
- request和response分别使用mvc的线程池
- service方法根据调用方式,使用
app-exec-或exec- - UncaughtException仅
void时,使用AsyncUncaughtExceptionHandler - FailedFuture或非
voidUncaughtException,使用ExceptionHandler
日志输出,大概如下,详见 AsyncControllerTest
## `Future` runs in 3 threads
XNIO-1 o.s.web.servlet.DispatcherServlet
XNIO-1 s.w.s.m.m.a.RequestMappingHandlerMapping
XNIO-1 p.f.w.s.a.c.TestAsyncController
exec-2 p.f.w.s.app.service.TestAsyncService
XNIO-1 o.s.w.c.request.async.WebAsyncManager : Async result set
XNIO-1 o.s.web.servlet.DispatcherServlet : Exiting but response remains open
## UncaughtException in exec thread-pool
exec-2 o.s.w.c.request.async.WebAsyncManager : Async error, dispatch
## FailedFuture in exec thread-pool
exec-2 o.s.w.c.request.async.WebAsyncManager : Async error, dispatch
XNIO-3 o.s.web.servlet.DispatcherServlet : "ASYNC" dispatch
XNIO-3 s.w.s.m.m.a.RequestMappingHandlerAdapter : Resume with async result
## `Callable` runs in 3 threads, with `applicationTaskExecutor`
XNIO-1 o.s.web.servlet.DispatcherServlet
XNIO-1 s.w.s.m.m.a.RequestMappingHandlerMapping
app-exec-2 p.f.w.s.app.service.TestAsyncService
app-exec-2 o.s.w.c.request.async.WebAsyncManager : Async result set
## sync Exception in exec thread-pool
app-exec-2 o.s.w.c.request.async.WebAsyncManager : Async error, dispatch
XNIO-3 o.s.web.servlet.DispatcherServlet : "ASYNC" dispatch
XNIO-3 s.w.s.m.m.a.RequestMappingHandlerAdapter : Resume with async result
## `DeferredResult` runs in 3 threads
XNIO-1 o.s.web.servlet.DispatcherServlet
XNIO-1 s.w.s.m.m.a.RequestMappingHandlerMapping
XNIO-1 p.f.w.s.a.c.TestAsyncController
exec-2 p.f.w.s.app.service.TestAsyncService
exec-2 o.s.w.c.request.async.WebAsyncManager : Async result set
XNIO-1 o.s.web.servlet.DispatcherServlet : Exiting but response remains open
## UncaughtException in web thread-pool
XNIO-1 o.s.w.c.request.async.WebAsyncManager : Async error, dispatch
## FailedFuture in exec thread-pool
exec-2 o.s.w.c.request.async.WebAsyncManager : Async error, dispatch
XNIO-3 o.s.web.servlet.DispatcherServlet : "ASYNC" dispatch
XNIO-3 s.w.s.m.m.a.RequestMappingHandlerAdapter : Resume with async result