Spring MVC异步处理简介
相关系列文章:
本文讲到的所有特性皆是基于Servlet 3.0 Async Processing的,不是基于Servlet 3.1 Async IO的。
Callable<?>
A
Callable<?>
can be returned when the application wants to produce the return value asynchronously in a thread managed by Spring MVC.
用于异步返回结果,使用的是Spring MVC的AsyncTaskExecutor
,Spring MVC使用CallableMethodReturnValueHandler
负责处理它。
下面是例子CallableController:
@RestController
public class CallableController {
@RequestMapping("callable-hello")
public Callable<String> hello() {
return () -> new SlowJob("CallableController").doWork();
}
}
用浏览器访问:http://localhost:8080/callable-hello 查看返回结果。
DeferredResult<?>
A
DeferredResult<?>
can be returned when the application wants to produce the return value from a thread of its own choosing.
用于异步返回结果,使用的是client code自己的thread,Spring MVC使用DeferredResultMethodReturnValueHandler
负责处理它。
下面是例子DeferredResultController:
@RestController
public class DeferredResultController {
@Autowired
@Qualifier("customExecutorService")
private ExecutorService executorService;
@RequestMapping("deferred-result-hello")
public DeferredResult<String> hello() {
DeferredResult<String> deferredResult = new DeferredResult<>();
executorService.submit(() -> {
try {
deferredResult.setResult(new SlowJob("DeferredResultController").doWork());
} catch (Exception e) {
deferredResult.setErrorResult(e);
}
});
return deferredResult;
}
}
在这个例子里使用了ExecutorService(见ExecutorServiceConfiguration),你也可以根据实际情况采用别的机制来给DeferredResult.setResult
。
用浏览器访问:http://localhost:8080/deferred-result-hello 查看返回结果。
ListenableFuture<?> or CompletableFuture<?>/CompletionStage<?>
AListenableFuture<?>
orCompletableFuture<?>
/CompletionStage<?>
can be returned when the application wants to produce the value from a thread pool submission.
用于异步返回结果,使用client code自己的thread pool,Spring MVC使用DeferredResultMethodReturnValueHandler
负责处理它。
下面是例子ListenableFutureController:
@RestController
public class ListenableFutureController {
@Autowired
@Qualifier("customExecutorService")
private ExecutorService executorService;
@RequestMapping("listenable-future-hello")
public ListenableFutureTask<String> hello() {
ListenableFutureTask<String> listenableFutureTask = new ListenableFutureTask<>(
() -> new SlowJob("ListenableFutureController").doWork());
executorService.submit(listenableFutureTask);
return listenableFutureTask;
}
}
用浏览器访问:http://localhost:8080/listenable-future-hello 查看返回结果。
下面是例子CompletionFutureController
@RestController
public class CompletionFutureController {
@RequestMapping("completable-future-hello")
public CompletableFuture<String> hello() {
return CompletableFuture
.supplyAsync(() -> new SlowJob("CompletionFutureController").doWork());
}
}
用浏览器访问:http://localhost:8080/completable-future-hello 查看返回结果。
ResponseBodyEmitter
A
ResponseBodyEmitter can be returned to write multiple objects to the response asynchronously; also supported as the body within a
ResponseEntity
.
用于异步的写入多个消息,使用的是client code自己的thread,Spring MVC使用ResponseBodyEmitterReturnValueHandler
负责处理它。
下面是例子ResponseBodyEmitterController
@RestController
public class ResponseBodyEmitterController {
@Autowired
@Qualifier("customExecutorService")
private ExecutorService executorService;
@RequestMapping("response-body-emitter-hello")
public ResponseBodyEmitter hello() {
ResponseBodyEmitter emitter = new ResponseBodyEmitter();
executorService.submit(() -> {
try {
for (int i = 0; i < 5; i++) {
String hello = new SlowJob("ResponseBodyEmitterController").doWork();
emitter.send("Count: " + (i + 1));
emitter.send("\n");
emitter.send(hello);
emitter.send("\n\n");
}
emitter.complete();
} catch (Exception e) {
emitter.completeWithError(e);
}
});
return emitter;
}
}
用浏览器访问:http://localhost:8080/response-body-emitter-hello 查看返回结果。
SseEmitter
An
SseEmitter can be returned to write Server-Sent Events to the response asynchronously; also supported as the body within a
ResponseEntity
.
作用和ResponseBodyEmitter
类似,也是异步的写入多个消息,使用的是client code自己的thread,区别在于它使用的是Server-Sent Events。Spring MVC使用ResponseBodyEmitterReturnValueHandler
负责处理它。
下面是例子SseEmitterController
@RestController
public class SseEmitterController {
@Autowired
@Qualifier("customExecutorService")
private ExecutorService executorService;
@RequestMapping("sse-emitter-hello")
public ResponseBodyEmitter hello() {
SseEmitter emitter = new SseEmitter();
executorService.submit(() -> {
try {
for (int i = 0; i < 5; i++) {
String hello = new SlowJob("SseEmitterController").doWork();
StringBuilder sb = new StringBuilder();
sb.append("Count: " + (i + 1)).append(". ").append(hello.replace("\n", ""));
emitter.send(sb.toString());
}
emitter.complete();
} catch (Exception e) {
emitter.completeWithError(e);
}
});
return emitter;
}
}
用浏览器访问:http://localhost:8080/sse-emitter-hello 查看返回结果。
StreamingResponseBody
A
StreamingResponseBody can be returned to write to the response OutputStream asynchronously; also supported as the body within a
ResponseEntity
.
用于异步write outputStream,使用的是Spring MVC的AsyncTaskExecutor
,Spring MVC使用StreamingResponseBodyReturnValueHandler
负责处理它。要注意,Spring MVC并没有使用Servlet 3.1 Async IO([Read|Write]Listener)。
下面是例子StreamingResponseBodyController
@RestController
public class StreamingResponseBodyController {
@RequestMapping("streaming-response-body-hello")
public StreamingResponseBody hello() {
return outputStream -> {
String hello = new SlowJob("CallableController").doWork();
outputStream.write(hello.getBytes());
outputStream.flush();
};
}
}
用浏览器访问:http://localhost:8080/streaming-response-body-hello 查看返回结果。
配置MVC Async
AsyncTaskExecutor
Spring MVC执行异步操作需要用到AsyncTaskExecutor
,这个可以在用WebMvcConfigurer.configureAsyncSupport
方法来提供(相关文档)。
如果不提供,则使用SimpleAsyncTaskExecutor
,SimpleAsyncTaskExecutor
不使用thread pool,因此推荐提供自定义的AsyncTaskExecutor
。
需要注意的是@EnableAsync
也需要用到AsyncTaskExecutor
,不过Spring MVC和它用的不是同一个。
顺带一提,EnableAsync
默认也使用SimpleAsyncTaskExecutor
,可以使用AsyncConfigurer.getAsyncExecutor
方法来提供一个自定义的AsyncTaskExecutor
。
例子见:MvcAsyncTaskExecutorConfigurer。
Interceptors
-
AsyncHandlerInterceptor
,使用WebMvcConfigurer.addInterceptors
注册 -
CallableProcessingInterceptor[Adapter]
,使用WebMvcConfigurer.configureAsyncSupport
注册 -
DeferredResultProcessingInterceptor[Adapter]
,使用WebMvcConfigurer.configureAsyncSupport
注册
官方文档:Intercepting Async Requests
WebAsyncManager
WebAsyncManager
是Spring MVC管理async processing的中心类,如果你可以阅读它的源码来更多了解Spring MVC对于async processing的底层机制。
参考资料
- Spring Web MVC Doc - Supported method return values
- Spring Web MVC Doc - Asynchronous Request Processing
- Spring Web MVC Doc - Configuring Asynchronous Request Processing
- Configuring Spring MVC Async Threads
- Spring MVC 3.2 Preview: Introducing Servlet 3, Async Support
- Spring MVC 3.2 Preview: Techniques for Real-time Updates
- Spring MVC 3.2 Preview: Making a Controller Method Asynchronous
- Spring MVC 3.2 Preview: Adding Long Polling to an Existing Web Application
- Spring MVC 3.2 Preview: Chat Sample