概述
Spring MVC 3.2 引入了基于Servlet 3的异步请求处理。我将撰写多篇博文来介绍这种新功能,并提供环境介绍来帮助你理解为什么以及如何使用该功能,本文是系列博文的第一篇。
早期发布版本的主要目的是寻求反馈。自从3.2 M1版本发布以来,我们已经从这里和JIRA收到了足够多的反馈。感谢尝试此功能并给予评论的每一个人。我们已经进行了很多改进,并且,我们还有更多时间来获取更多反馈。
初识
从编程模型的角度来看,这种新功能貌似很简单。一个控制器方法能返回一个java.util.concurrent.Callable回调方法来异步的完成处理。Spring MVC将在TaskExecutor的帮助下在一个单独的线程中调用该回调方法。下面的代码是以前的写法:
// 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 集成通道发送一个事件来处理,然后返回一个确认ID给客户端来查询处理结果。
在另一些情况下,必须要返回处理结果,那么我们就需要把处理过程从Servlet容器中解耦出来,否则我们将耗光线程池。Servlet 3提供了这种支持,Servlet (或者Spring MVC的控制器) 能够指示response在Servlet容器的线程退出之后保持开放状态。
要实现这种效果, Servlet 3 web应用可以调用request.startAsync(),然后在其他独立的线程中使用返回的AsyncContext来继续向response写入信息。同时,从客户端的角度来看,request仍然像任何其他的HTTP的request-response交互一样,只是耗费了更长的时间而已。下面是事件的顺序:
2KB项目(www.2kb.com,源码交易平台),提供担保交易、源码交易、虚拟商品、在家创业、在线创业、任务交易、网站设计、软件设计、网络兼职、站长交易、域名交易、链接买卖、网站交易、广告买卖、站长培训、建站美工等服务