本部分示例见这个项目的 mvc 分支下的 AsyncController.java


  Spring MVC 3.2 中引进了基于异步请求处理的 Servlet 3。除了返回一个值,一个控制器方法现在可以返回一个java.util.concurrent.Callable并生产来自 Spring MVC 管理的线程的返回值。同时主 Servlet 容器线程退出、释放并允许处理其他请求。Spring MVC 在 TaskExecutor 的帮助下,在一个独立的线程中调用 Callable,当 Callable 返回时,请求被发回 Servlet 容器,使用 Callable 的返回值继续执行。这里有一个这样的控制器方法的例子:

@PostMapping
public Callable<String> processUpload(final MultipartFile file) 
{
    return new Callable<String>() 
    {
        public String call() throws Exception 
        {
            // ...
            return "someView";
        }
    };
}

  这个控制器方法的另一个选择是返回一个DeferredResult实例。这种情况下,返回值可以由任何线程产生,比如一个没有被 Spring MVC 管理的线程。比如,结果可能产生于外部事件的响应,比如一个 JMS 消息,一个定时任务等。这里有一个这样的控制器方法的例子:

@RequestMapping("/quotes")
@ResponseBody
public DeferredResult<String> quotes() 
{
    DeferredResult<String> deferredResult = new DeferredResult<String>();
    // Save the deferredResult somewhere..
    return deferredResult;
}

// In some other thread...
deferredResult.setResult(data);

  如果没有任何对 Servlet 3.0 中异步请求处理特性的了解的话,这可能很难理解。去了解一下会很有帮助。这里列出几个这个机制的基本事实:

  • 通过request.startAsync()调用,一个 ServletRequest 可以被置为异步模式。这么做的主要影响是,Servlet,以及任何 Filter,可以退出,但是响应依旧会保持开放来允许之后完成处理过程。

  • request.startAsync()的调用返回 AsyncContext,AsyncContext 可以被用于异步处理之上的进一步控制。比如它提供了方法调度功能,这很像 Servlet API 中的 forward,但是它允许应用程序继续在 Servlet 容器线程中进行请求处理。

  • ServletRequest 提供对当前 DispatcherType 的访问,DispatcherType 可以用于区别处理初始化请求、异步调度、forward 和其他调度器(dispatcher)类型。

  有了上面的意识,下面是用于带有 Callable 的异步请求处理的事件序列:

  • 控制器返回一个 Callable

  • Spring MVC 开始异步处理,并把 Callable 提交给一个 TaskExecutor 用于在一个单独的线程中处理

  • DispatcherServlet 和所有的 Filter 退出 Servlet 容器线程,但是响应保持打开

  • 这个 Callable 产生一个结果,Spring MVC 把这个请求调回 Servlet 容器继续处理

  • DispatcherServlet 继续执行,并继续处理来自 Callable 的异步产生的结果

  DeferredResult 的事件序列很相似,除了它应该由应用程序从任何线程中来产生异步结果:

  • 控制器返回一个 DeferredResult,并把它保存在内存中的队列或者列表中用于访问

  • Spring MVC 开始异步处理

  • DispatcherServlet 和所有配置的 Filter 退出请求处理线程,但是响应依旧打开

  • 应用程序设置来自一些线程中的 DeferredResult,Spring MVC 把请求调回 Servlet 容器

  • DispatcherServlet 再次被调用,并继续处理异步产生的结果

  要了解更多使用异步请求处理的动机的背景,以及什么时候或为什么使用它,请读这个博客文章系列.


因为所学有限,这一部分并没有真正完成。这里先占坑,日后再行补充。


行一
51 声望35 粉丝

人不可能记住所有的细节