领先一步
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容器的线程池,影响可伸缩性。
在某些情况下,您可以在后台作业完成处理的同时立即返回给客户端。例如,发送电子邮件、启动数据库作业以及其他“即发即弃”(fire-and-forget)场景,这些可以通过Spring的 @Async 支持,或者通过将事件发布到 Spring Integration 通道来处理,然后返回一个客户端可以使用该确认ID来查询结果。
在其他需要结果的情况下,我们需要将处理与Servlet容器线程解耦,否则我们将耗尽其线程池。Servlet 3提供了这样的支持,其中Servlet(或Spring MVC控制器)可以在Servlet容器线程退出后指示响应保持打开状态。
为了实现这一点,Servlet 3 Web应用程序可以调用 request.startAsync() 并使用返回的 AsyncContext 从其他独立线程继续写入响应。同时,从客户端的角度来看,请求仍然像任何其他HTTP请求-响应交互一样。只是完成需要更长时间。以下是事件序列:
request.startAsync(),保存 AsyncContext,然后返回AsyncContext 完成响应当然,Servlet异步支持还有很多内容。您可以找到 各种 示例 和 文档,但以上总结了您需要了解的基本、最低概念。 下一篇博文 将介绍异步请求处理的第二个动机——浏览器接收实时信息更新的需求。