Spring 4.x官方参考文档中文版——第21章 Web MVC框架(12)

21.3.4 异步请求处理

       SpringMVC 3.2介绍了基于Servlet3的异步请求处理。Controller控制器中的方法现在可以不单是返回一个值,现在还可以返回一个java.util.concurrent.Callable,也可以从Spring MVC管理的线程中返回一个值。这样的话,主要的Servlet容器的线程就被释放,可以用来处理其他请求了。Spring MVC会在TaskExecutor的帮助下,在单独的线程中调用Callable对象,并且当Callable对象返回时,这个请求会被分派回Servlet容器,使用这个Callable对象的返回值来恢复处理这个请求。下面是一个例子:

@RequestMapping(method=RequestMethod.POST)
public Callable<String> processUpload(final MultipartFile file) {

    return new Callable<String>() {
        public String call() throws Exception {
            // ...
            return "someView";
        }
    };

}


Controller控制器也可以返回一个DeferredResult实例。这种情况下,那些没有被Spring MVC所管理的返回值也能从任何线程中产生。比如:在响应中,结果可能是,在响应中产生一些类似JMS消息,定时任务等等的外部事件。下面是一个例子:

@RequestMapping("/quotes")
@ResponseBody
public DeferredResult<String> quotes() {
    DeferredResult<String> deferredResult = new DeferredResult<String>();
    // 在某处保存deferredResult..
    return deferredResult;
}

// 在其他某个线程中…
deferredResult.setResult(data);

       如果没有关于Servlet 3.0异步请求处理特性的知识,可能比较难理解。下面是关于Servlet3.0基础机制的要点:

  • 通过调用request.startAsync(),能够把ServletRequest放到异步模式中。这样做会导致Servlet或任何Filters(过滤器)退出后,响应还是保持开通状态,来继续完成它的处理过程。
  • 调用request.startAsync()返回的AsyncContext能在整个异步处理过程中使用。例如:它提供了一个方法”dispatch”,这个方法与Servlet API中的forward类似,只是不能在应用里的Servlet容器的线程中,恢复请求的处理过程。
  • ServletRequest提供对现有DispatcherType的访问,DispatcherType能用来在初始化的请求处理过程,一个异步的dispatch,一个forward,和其他dispatcher(分派器)类型区别开来。

记住了上面的要点,来看看下面的内容--使用Callable来处理异步请求时的事件顺序:

  • Controller返回一个Callable
  • Spring MVC开始异步处理过程,并且把Callable上交到TaskExecutor,在一个单独的线程中处理。
  • DispatcherServlet和所有Filter从Servlet容器中退出,但是,响应还是保持开通状态。
  • Callable产生了一个结果,并且Spring MVC把该请求分派回Servlet容器,来恢复处理过程。
  • DispatcherServlet被再次调用,并使用从Callable异步产生的结果来处理恢复的状态。

在DeferredResult中除了它取决于应用中,任何线程产生的异步结果外,它的顺序也是与Callable十分相似的:

  • Controller返回一个DeferredResult,并保存到它能够访问的内存中的queue或者list中。
  • Spring MVC开始异步处理过程。
  • DispatcherServlet和所有配置了的Filter退出该请求的处理的线程,但是响应还是处于开通状态。
  • 该应用中从一些线程中设置了DeferredResult,然后Spring MVC分派该请求回Servlet容器中。
  • DispatcherServlet被再次调用,并使用异步产生了的结果处理恢复状态。

需要详细了解异步请求处理过程的行为或者了解为何,何时使用它,请参阅这个博客发表的系列文章

 

异步请求的异常处理

       如果在一个controller方法中,Callable在执行中抛出了错误会怎样?简短版的答案是:与controller方法抛出错误时发生的状况是一样的。它也是使用常规的异常处理机制。加长版答案是:当Callable抛出了异常,SpringMVC把这个Exception当作结果,分派到Servlet容器,这将导致恢复请求处理时,是使用的这个Exception,而不是一个controller方法的返回值。当使用DeferredResult时,你可以选择调用setResult或setErrorResult来处理Exception实例。

 

拦截异步请求

       HandlerInterceptor也可以实现AsyncHandlerInterceptor来实现afterConcurrentHandlingStarted的回调。当异步的处理过程开始时,这个回调代替了postHandle和afterCompletion。

       HandlerInterceptor也能注册CallableProcessingInterceptor或DefferedResultProcessingInterceptor来与一个异步请求的生命周期深度结合,例如:处理一个会超时的事件。详见AsyncHandlerInterceptor的javadoc文档。

       DefferredResult类也提供如onTimeout(Runnable)和onCompletion(Runnable)的方法。详见DeferredResult的javadoc文档。

       当使用Callable时,你也能用WebAsyncTask的实例来封装它,WebAsyncTask也能提供timeout和completion的注册方法。


  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值