Spring中的异步Servlet

本人花费半年的时间总结的《Java面试指南》已拿腾讯等大厂offer,已开源在github ,欢迎star!

本文GitHub https://github.com/OUYANGSIHAI/JavaInterview 已收录,这是我花了6个月总结的一线大厂Java面试总结,本人已拿大厂offer,欢迎star

原文链接:blog.ouyangsihai.cn >> Spring中的异步Servlet

自从Servlet3推出异步之后,Spring3.2已经开始增加了对Servlet异步的支持。

在高并发的Web场景中,如果出现处理请求的过程中出现较长的阻塞,对整个服务的性能影响是致命的,大量的请求长时间无返回会占用Servlet容器的工作线程,造成容器线程池耗尽,从而无法对外提供服务。

那么Servlet异步的初衷就是来解耦Servlet线程和我们应用的具体业务逻辑线程的,从而把Servlet请求线程(即Servlet容器的dispatch线程)快速返回给容器,以便给其它请求提供服务。下面这张图展示的比较清楚(图片来源于网络)

Spring中的异步Servlet

今天在这里主要给大家讲解下Spring中使用异步servlet的方式,以及实现原理。

使用方式

下面边张图便是Spring中使用异步请求的方式

Spring中的异步Servlet

我们看到,与普通的Controller方法的区别在于,handler方法返回的是Callable(还有其它的方式如:返回DeferredResult等),那么返回一个Callable就怎么成异步的了呢,我们得继续往底层看下Spring的源码

实现原理

在Spring中,处理servlet请求的核心代码在这里

Spring中的异步Servlet

方法第一行是真正执行业务逻辑的方法(也就是Controller里具体方法内容),在这一步,不管是否是异步请求,都要执行这一步,那么你可能要问,那异步的处理在哪里呢?先别急,你想想看,我们的异步方法返回的什么?没错,是Callable,而我们真正的业务逻辑是在Callable内部的call()中,所以现在只是返回一个callable对象,call()并没有调用。那么何时才真正调用call()中真正的业务逻辑呢,继续看上图

这一行恰恰是关键,顺便说下,在Spring中,有一系列的HandlerReturnValueHandler接口的实现,它们都是用来处理Controller中handler方法返回值的。在这里,我们异步方法的返回值是Callable,那就找Callable相关的返回值处理器,是这个类:

具体执行方法如下:

Spring中的异步Servlet

上图选中的一行,正是异步的关键,继续往里跟:

Spring中的异步Servlet

我们看到,我们定义的callable被交给了一个executor执行,此时原有的Servlet请求线程就返回了(返回的同时ServletResponse并没有被提交)。

接下来呢,异步任务完了之后何时返回给用户呢?

我们看上边run()方法里的最后一行

执行到这一行,异步任务已经被执行完了,这一行的作用就是把剩下来的事又交给容器,让容器把结果返回给客户端。

这里有一个关键问题是,怎么返回给容器,容器又怎么知道把结果给谁呢

我们看Servlet3中的ServletRequest中有一个方法,也就是请求转为异步的方法

它会返回一个AsyncContext,这个接口正是整个异步请求生命周期的关键。

它持有异步请求中的关键上下文,也就是request,reponse

Spring中的异步Servlet

此外还有两个重要的方法

上边说到异步任务执行完之后,把结果返回给Servlet容器,就是通过dispatch()方法完成的,具体的dispatch实现,不同的Servlet容器有不同的实现。

总结
Servlet3异步请求该用在什么样的场景呢?引用Servlet3规范中的原话:

Some times a filter and/or servlet is unable to complete the processing of a request without waiting for a resource or event before generating a response. For example, a servlet may need to wait for an available JDBC connection, for a response from a remote web service, for a JMS message, or for an application event, before proceeding to generate a response. Waiting within the servlet is an inefficient operation as it is a blocking operation that consumes a thread and other limited resources. Frequently a slow resource such as a database may have many threads blocked waiting for access and can cause thread starvation and poor quality of service for an entire web container.

也就是说,后端应用中有大IO事务的情况,采用异步Servlet是明智的选择。

Spring中的异步Servlet

欢迎关注,期待与您的交流,让我们携手在通往牛逼的小路上徐徐前行。

本人花费半年的时间总结的《Java面试指南》已拿腾讯等大厂offer,已开源在github ,欢迎star!

本文GitHub https://github.com/OUYANGSIHAI/JavaInterview 已收录,这是我花了6个月总结的一线大厂Java面试总结,本人已拿大厂offer,欢迎star

原文链接:blog.ouyangsihai.cn >> Spring中的异步Servlet


 上一篇
面试中常问到的Spring注入循环依赖 面试中常问到的Spring注入循环依赖
在Spring注入的机制里,人们常提到的一个问题是循环依赖,那么什么是循环依赖,假设有两个bean,你中有我,我中有你,这样一来,在容器创建bean的时候是如何处理的呢,是鸡生蛋,还是蛋生鸡,这是个问题。 我们先来看两个小例子 A B类
2021-04-05
下一篇 
Spring类型转换机制 Spring类型转换机制
1Spring中的类型转换,主要用在两种场景 Bean的解析,Spring中bean定义的属性都是以文本的形式,构造bean的时候需要转成相应的各种Java类型 Spring Mvc的request请求生命周期中,需要把http的
2021-04-05