领先一步
VMware 提供培训和认证,以加速您的进步。
了解更多最后更新于 2012年11月5日 (Spring MVC 3.2 RC1)
概述
Spring MVC 3.2 引入了基于 Servlet 3 的异步请求处理。这是涵盖此新功能并提供理解如何以及为何使用它的背景的多篇博文中的第一篇。
早期版本的首要目的是寻求反馈。自从 3.2 M1 版本发布后,我们在这里和 JIRA 中都收到了大量反馈。感谢所有尝试并发表评论的人!已经进行了许多更改,并且仍然有时间提供更多反馈!
概览
从编程模型的角度来看,新功能看起来非常简单。控制器方法现在可以返回一个 java.util.concurrent.Callable
来异步完成处理。Spring MVC 然后将在单独的线程中使用 TaskExecutor
调用 Callable
。以下是之前的代码片段
// Before
@RequestMapping(method=RequestMethod.POST)
public String processUpload(final MultipartFile file) {
// ...
return "someView";
}
// After
@RequestMapping(method=RequestMethod.POST)
public Callable<String> processUpload(final MultipartFile file) {
return new Callable<String>() {
public Object call() throws Exception {
// ...
return "someView";
}
};
}
控制器方法还可以返回一个 DeferredResult
(Spring MVC 3.2 中的新类型)以在 Spring MVC 未知的线程中完成处理。例如,响应 JMS 或 AMQP 消息、Redis 通知等。以下是另一个代码片段
@RequestMapping("/quotes")
@ResponseBody
public DeferredResult<String> quotes() {
DeferredResult<String> deferredResult = new DeferredResult<String>();
// Add deferredResult to a Queue or a Map...
return deferredResult;
}
// In some other thread...
deferredResult.setResult(data);
// Remove deferredResult from the Queue or Map
以上示例引发了许多问题,我们将在后续文章中详细介绍。现在,我将从提供围绕这些功能的一些背景开始。
Web 应用程序中异步性的动机
Web 应用程序中异步性的最基本动机是处理需要更长时间才能完成的请求。可能是缓慢的数据库查询、对外部 REST API 的调用或其他一些 I/O 绑定操作。此类较长的请求可以快速耗尽 Servlet 容器线程池并影响可扩展性。
在某些情况下,您可以在后台作业完成处理时立即返回客户端。例如,发送电子邮件、启动数据库作业和其他一些代表启动并忘记的场景,可以使用 Spring 的 @Async 支持或通过将事件发布到 Spring Integration 通道来处理,然后返回客户端可用于查询结果的确认 ID。
在其他情况下,如果需要结果,我们需要将处理与 Servlet 容器线程分离,否则我们将耗尽其线程池。Servlet 3 提供了这种支持,其中 Servlet(或 Spring MVC 控制器)可以指示在 Servlet 容器线程退出后应保持响应打开。
为了实现这一点,Servlet 3 Web 应用程序可以调用 request.startAsync()
并使用返回的AsyncContext
从其他一些单独的线程继续写入响应。同时,从客户端的角度来看,请求仍然看起来像任何其他 HTTP 请求-响应交互。它只是需要更长的时间才能完成。以下是事件顺序
request.startAsync()
,保存 AsyncContext
并返回AsyncContext
来完成响应当然,Servlet 异步支持还有更多内容。您可以找到 各种 示例 和 文章,但以上总结了您需要了解的基本最小概念。下一篇文章 涵盖了异步请求处理的第二个动机——浏览器需要实时接收信息更新。