Spring MVC 3.2 技术预览(一):Servlet 3介绍,异步支持
概述
Spring MVC 3.2 M1 引入了基于 Servlet 3.0 支持的异步请求处理功能。我将针对 Spring MVC 3.2 的新特性发布一系列文章,通过对背景知识和相关内容的充分介绍,帮助你理解为什么需要这些新特性,以及如何使用它们。这是系列文章中的第一篇。
Spring MVC 3.2 的更新内容已经可以在 Spring Framework Github 中查看。你也可以将 http://repo.springsource.org/snapshot 配置到你的项目仓库中,以获取快照版本。在后续文章中,我将提供更多的源码示例链接。
如果你想现在就尝试这些新特性,可以在 GitHub 上签出 spring-mvc-async 分支中的 spring-mvc-showcase 项目,并通过 提交记录 查看其中的更新信息。
特性预览
从编程模型的角度来看,新功能看似简单。现在,控制器(Controller)的方法可以返回 Callable 类型来完成异步请求处理。Spring MVC 3.2 会在 TaskExecutor 的帮助下,在一个独立的线程中调用这个返回值。示例代码如下:
@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 中的新成员),并在任意线程中完成异步处理。例如,对某个外部事件(如 JMS 消息、AMQP 消息、Redis 消息等)作出反应。下面是另一个代码片段:
@RequestMapping("/quotes")
@ResponseBody
public DeferredResult quotes() {
DeferredResult deferredResult = new DeferredResult();
// Add deferredResult to a Queue or a Map...
return deferredResult;
}
// In some other thread..
// Set the return value on the deferredResult
deferredResult.set(data);大家可能对上面的代码片段有很多疑问,我会在后续文章中给出更多的细节信息。在深入了解之前,我先介绍一些相关的技术背景知识。
异步请求背景:长连接与线程模型
当前一些网络应用最常用的异步处理方式就是长连接方式,例如运行一个缓慢的数据库查询、调用一个外部的 REST API 或者执行其他 I/O 操作。这些方式很快就会消耗光 Servlet 容器的线程池,影响程序的可扩展性。
在一些情况下,你可能需要等待一个处理完成,例如发送邮件、执行数据库操作等。在这种“即发即忘”(fire-and-forget)情况下,你可以使用 Spring 注解 @Async 或设置 Spring Integration 事件并迅速返回,也许还可以返回一个用于确认的 ID,为后续的响应所用。这在 Spring MVC 3.2 之前就可以实现,并且可以避免请求死锁。
对于需要在结果返回之前释放资源的其他情况,你需要先释放处理请求的 Servlet 容器线程来提高程序的可扩展性。为了实现这个功能,Servlet 3 允许一个 Servlet 在返回请求之后声明保持响应为打开状态,这样请求就可以在一个独立线程中完成。
具体来说,可以调用 Servlet 3 中的 request.startAsync() 方法,并使用返回的 AsyncContext 在一个独立线程内继续写入(并最终完成)响应。这在客户端看来没有任何变化,请求仍然看起来像是其他 HTTP 标准的“请求—响应”一样。但是,在服务器端看来,异步请求处理可以让你以扩展性更好的方式处理请求。
Servlet 3 规范定义了异步请求处理的标准流程。关于 Servlet 对异步请求处理的支持,还有很多内容,你可以找到 很多 示例 和 文章(注:部分外链可能因网络原因无法访问),但是上面总结的这些是所需要的最基本的概念。
总结
在下一篇文章中,我将介绍第二种异步请求处理的方式:客户端浏览器无延时的实时获取服务器的更新信息。过去已经发展出了很多方式实现这个功能,一些停留在 HTTP 标准的“请求—响应”的语义环境下,另一些则以更好的方式实现。
原文地址:http://blog.springsource.org/2012/05/06/spring-mvc-3-2-preview-introducing-servlet-3-async-support/
说明:本文基于 Spring MVC 3.2 预览版编写,属于历史技术文章。当前 Spring Framework 已演进至 6.x 版本,Servlet 规范也已更新至 6.0。文中提到的Callable与DeferredResult异步处理机制在现代版本中依然适用且更为成熟,但具体配置与依赖版本请以官方最新文档为准。
版权声明:本文为原创文章,版权归 戴老师的博客 所有,转载请联系博主获得授权。
本文地址:https://1diff.fun/archives/spring-mvc-32-ji-shu-yu-lan--yi-servlet-3-jie-shao--yi-bu-zhi-chi.html
如果对本文有什么问题或疑问都可以在评论区留言,我看到后会尽量解答。