java webasynctask_007-优化web请求三-异步调用【WebAsyncTask】

一、什么是同步调用

f60d33c936dc2e7d02c3fd0b5e9b900f.png

浏览器发起请求,Web服务器开一个线程处理,处理完把处理结果返回浏览器。好像没什么好说的了,绝大多数Web服务器都如此般处理。现在想想如果处理的过程中需要调用后端的一个业务逻辑服务器

434530c507b2878a28588a1e8796d31a.png

请求处理线程会在Call了之后等待Return,自身处于阻塞状态。这也是绝大多数Web服务器的做法。一般此种做法主要适用于,后端处理响应比较快,并且并发数比较低的情况。

主要弊端,在高并发请求下,请求处理线程的短缺!因为请求处理线程的总数是有限的,如果类似的请求多了,所有的处理线程处于阻塞的状态,那新的请求也就无法处理了,也就所谓影响了服务器的吞吐能力。要更加好地发挥服务器的全部性能,就要使用异步。

二、什么是异步

ab23548ea5b9880c8a9822c9a43bf3ee.png

最大的不同在于请求处理线程对后台处理的调用使用了“invoke”的方式,就是说调了之后直接返回,而不等待,这样请求处理线程就“自由”了,它可以接着去处理别的请求,当后端处理完成后,会钩起一个回调处理线程来处理调用的结果,这个回调处理线程跟请求处理线程也许都是线程池中的某个线程,相互间可以完全没有关系,由这个回调处理线程向浏览器返回内容。这就是异步的过程。

带来的改进是显而易见的,请求处理线程不需要阻塞了,它的能力得到了更充分的使用,带来了服务器吞吐能力的提升。

三、使用Spring MVC 和Servlet3异步线程

3.1、前提

要使用Spring MVC的异步功能,你得先确保你用的是Servlet 3.0或以上的版本,Maven中如此配置:

javax.servlet

javax.servlet-api

3.1.0

provided

Spring MVC 3.2以后版本开始引入了基于Servlet3的异步请求处理

3.2、概述

相比以前,控制器方法已经不一定需要一个值,而是可以直接返回一个Callable对象,并通过Spring MVC所管理的线程来产生返回值,与此同时,Servlet容器的主线程则可以退出并释放其资源,同时也允许容器去处理其它请求。通过一个TaskExecutor,Spring MVC可以在另外的线程中调用Callable。当Callable返回时,请求在携带Callable返回的值,再次被分配到Servlet容器中恢复处理流程。

官方文档中说DeferredResult和Callable都是为了异步生成返回值提供基本的支持。简单来说就是一个请求进来,如果你使用了DeferredResult或者Callable,在没有得到返回数据之前,DispatcherServlet和所有Filter就会退出Servlet容器线程,但响应保持打开状态,一旦返回数据有了,这个DispatcherServlet就会被再次调用并且处理,以异步产生的方式,向请求端返回值。

这么做的好处就是请求不会长时间占用服务连接池,提高服务器的吞吐量。

1、Servlet 3.0异步请求运作机制的部分原理

a.Servlet请求ServletRequest可以通过调用request.startAsync()方法而进入异步模式,这样做的主要结果就是该Servlet以及所有的过滤器都可以结束但其相应(Response)会留待异步处理结束后在返回调用。

b.request.startAsync()方法会返回一个AsyncContext对象,可以用他对异步处理进行进一步的控制和操作,比如说他也提供了一个与反转(forward)很相似的dispatch方法,只不过他允许应用恢复Servlet容器的请求处理进程。

c.ServletRequest提供了获取当前DispatherType的方式,后者可以用来区别当前处理的是原始请求,异步分发请求,转向或者是其它类型的请求分发类型。

2、Callable的异步请求被处理时所发生的事件

官方介绍

Controller returns a Callable.

Spring MVC calls request.startAsync() and submits the Callable to a TaskExecutorforprocessing in a separate thread.

Meanwhile the DispatcherServlet and all Filter’s exit the Servlet container thread but the response remains open.

Eventually the Callable produces a result and Spring MVC dispatches the request back to the Servlet container to complete processing.

The DispatcherServlet is invoked again and processing resumes with the asynchronously producedreturn value from the Callable.

1》Controller返回Callable

2》Spring MVC调用request.startAsync()并将Callable提交给TaskExecutor,以便在单独的线程中进行处理。

3》同时DispatcherServlet和所有Filter都退出Servlet容器线程,但响应仍保持打开状态。

4》最终,Callable生成一个结果,Spring MVC将请求调度回Servlet容器以完成处理。

5》再次调用DispatcherServlet,并使用来自Callable的异步生成的返回值继续处理。

流程上大体与DeferredResult类似,只不过Callable是由TaskExecutor来处理的,而TaskExecutor继承自java.util.concurrent.Executor。我们来看一下它的源代码,它也是在WebAysncManager中处理的:

8f900a89c6347c561fdf2122f13be562.png

961ddebeb323a10fe0623af514929fc1.png

/*** Use the given {@linkWebAsyncTask} to configure the task executor as well as

* the timeout value of the {@codeAsyncWebRequest} before delegating to

* {@link#startCallableProcessing(Callable, Object...)}.

*@paramwebAsyncTask a WebAsyncTask containing the target {@codeCallable}

*@paramprocessingContext additional context to save that can be accessed

* via {@link#getConcurrentResultContext()}

*@throwsException if concurrent processing failed to start*/

public void startCallableProcessing(final WebAsyncTask> webAsyncTask, Object... processingContext) throwsException {

Assert.notNull(webAsyncTask,"WebAsyncTask must not be null");

Assert.state(this.asyncWebRequest != null, "AsyncWebRequest must not be null");

Long timeout=webAsyncTask.getTimeout();if (timeout != null) {this.asyncWebRequest.setTimeout(timeout);

}

AsyncTaskExecutor executor=webAsyncTask.getExecutor();if (executor != null) {this.taskExecutor =executor;

}

List interceptors = new ArrayList();

interceptors.add(webAsyncTask.getInterceptor());

interceptors.addAll(this.callableInterceptors.values());

interceptors.add(timeoutCallableInterceptor);final Callable> callable =webAsyncTask.getCallable();final CallableInterceptorChain interceptorChain = newCallableInterceptorChain(interceptors);this.asyncWebRequest.addTimeoutHandler(newRunnable() {

@Overridepublic voidrun() {

logger.debug("Processing timeout");

Object result=interceptorChain.triggerAfterTimeout(asyncWebRequest, callable);if (result !=CallableProcessingInterceptor.RESULT_NONE) {

setConcurrentResultAndDispatch(result);

}

}

});this.asyncWebRequest.addCompletionHandler(newRunnable() {

@Overridepublic voidrun() {

interceptorChain.triggerAfterCompletion(asyncWebRequest, callable);

}

});

interceptorChain.applyBeforeConcurrentHandling(this.asyncWebRequest, callable);

startAsyncProcessing(processingContext);//启动线程池的异步处理

try{this.taskExecutor.submit(newRunnable() {

@Overridepublic voidrun() {

Object

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值