Servlet 3.0笔记之异步请求相关方法和AsyncContext

Servlet3.0引入异步处理来解决长时间运行请求占用线程资源的问题,通过AsyncContext可以在不阻塞主线程的情况下处理业务,提高系统性能。请求在遇到异步时仅释放线程资源,请求和响应对象可在子线程中获取,待处理完成后返回客户端。
摘要由CSDN通过智能技术生成

Servlet 3.0笔记之异步请求相关方法和AsyncContext

1、传统Servlet处理
 Web容器会为每个请求分配一个线程,默认情况下,响应完成前,该线程占用的资源都不会被释放。若有些请求需要长时间(例如长处理时间运算、等待某个资源),就会长时间占用线程所需资源,若这类请求很多,许多线程资源都被长时间占用,会对系统的性能造成负担。

2、新特性:异步处理
 Servlet 3.0新增了异步处理,可以先释放容器分配给请求的线程与相关资源,减轻系统负担,原先释放了容器所分配线程的请求,其响应将被延后,可以在处理完成(例如长时间运算完成、所需资源已获得)时再对客户端进行响应。

 Servlet 3.0 之前,一个普通 Servlet 的主要工作流程大致如下:
第一步,Servlet 接收到请求之后,可能需要对请求携带的数据进行一些预处理;
第二步,调用业务接口的某些方法,以完成业务处理;
第三步,根据处理的结果提交响应,Servlet 线程结束。
其中第二步的业务处理通常是最耗时的,这主要体现在数据库操作,以及其它的跨网络调用等,在此过程中,Servlet 线程一直处于阻塞状态,直到业务方法执行完毕。在处理业务的过程中,Servlet 资源一直被占用而得不到释放,对于并发较大的应用,这有可能造成性能的瓶颈。对此,在以前通常是采用私有解决方案来提前结束 Servlet 线程,并及时释放资源。

 Servlet 3.0 针对这个问题做了开创性的工作,现在通过使用 Servlet 3.0 的异步处理支持,之前的 Servlet 处理流程可以调整为如下的过程:
第一步,Servlet 接收到请求之后,可能首先需要对请求携带的数据进行一些预处理;
第二步,Servlet 线程将请求转交给一个异步线程来执行业务处理,线程本身返回至容器,
第三步,Servlet 还没有生成响应数据,异步线程处理完业务以后,可以直接生成响应数据(异步线程拥有 ServletRequest 和 ServletResponse 对象的引用),或者将请求继续转发给其它 Servlet。
Servlet 线程不再是一直处于阻塞状态以等待业务逻辑的处理,而是启动异步线程之后可以立即返回。

AsyncContext源码

@Override
public AsyncContext startAsync() {
    return startAsync(getRequest(),response.getResponse());
}

@Override
public AsyncContext startAsync(ServletRequest request,
                               ServletResponse response) {
    if (!isAsyncSupported()) {
        IllegalStateException ise =
            new IllegalStateException(sm.getString("request.asyncNotSupported"));
        log.warn(sm.getString("coyoteRequest.noAsync",
                              StringUtils.join(getNonAsyncClassNames())), ise);
        throw ise;
    }

    if (asyncContext == null) {
        asyncContext = new AsyncContextImpl(this);
    }

    asyncContext.setStarted(getContext(), request, response,
                            request==getRequest() && response==getResponse().getResponse());
    asyncContext.setTimeout(getConnector().getAsyncTimeout());

    return asyncContext;
}

AsyncContext应用demo

在这里插入图片描述

使用场景

在这里插入图片描述在这里插入图片描述
该方法主要是将客户端的长轮询请求添加到某个东西中去:服务端将客户端的长轮询请求封装成一个叫 ClientLongPolling 的任务,交给 scheduler 去执行,但是request,和response不会立即返回客户端直到asyncContext.complete才返回,generateResponse是nacos客户端长轮询请求达到超时时间30秒或者检测到配置变更才会调用

api说明

 在ServletRequest中增加的有关异步相关方法分为:
startAsync(servletRequest, servletResponse) 传入指定的request和response对象,便于在AsyncContext中重复使用(这样被Filter、Servlet包装过的请求、相应对象才会在异步的环境下继续生效)。
 startAsync() 若request或者response被包装,将失去预期的效果。
isAsyncSupported() 和 isAsyncStarted()
辅助性的方法,用于判断当前请求是否支持异步或者异步已经开始。
 getAsyncContext()
需要在异步启动之后才能够访问,否则会报异常。
在AsyncContext中分发的方法有三个,不太容易区分:
 AsyncContext.dispatch()
若当前AsyncContext由ServletRequest.startAsync(ServletRequest, ServletResponse)方法启动,返回的地址可以通过HttpServletRequest.getRequestURI()得到。
否则,分发的地址则是当前URL request对象最后一次分发的地址。
虽有些拗口,两者分发的地址大部分情况下一致;但尽量使用带有参数的异步上下文启动器。
如本例中请求/asyncDispatch2Async?disUrl=self,执行dispatch()方法之后,自身会再次分发到自身,包括传递的参数。
 AsyncContext.dispatch(String path)
等同于ServletRequest.getRequestDispatcher(String),算是一个快捷方法。
可以转向一个同步或异步的servlet,或者JSP,或其它资源地址等。
AsyncContext.dispatch(ServletContext context, String path)
请求的地址将在给定的上下文里面(ServletContext),有可能传入的上下文与当前站带你应用的上下文有所区别

总结

 容器里边实现 request 的时候尽量复用,而不是收回,但是组件的异步处理功用被启用(request 上调用了 startAsync 办法)。request 的生命周期在遇到异步的时候有点特殊,仅仅会释放容器分配给请求的线程与相关资源但是request和response不会被释放可以在子线程获取,待子线程耗时操作执行完才会一起释放返回客户端

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值