内容简介:应用服务器的web容器通常会为每个请求分配一个服务线程。在重负载的场景下,容器需要大量的线程去服务所有客户端请求。服务可扩展性的限制包括内存不足或者耗尽容器线程。创建可扩展web程序,你必须确保没有关联请求的线程是空闲的,所以容器可以使用他们处理新请求。这里有两个关联请求的线程空闲的两个场景:这些场景代表限制web程序可扩展性的阻塞操作。异步处理是指给这些阻塞操作分配一个新线程,并把关联请求处理的线程返回给web容器。
应用服务器的web容器通常会为每个请求分配一个服务线程。在重负载的场景下,容器需要大量的线程去服务所有客户端请求。服务可扩展性的限制包括内存不足或者耗尽容器线程。创建可扩展web程序,你必须确保没有关联请求的线程是空闲的,所以容器可以使用他们处理新请求。
这里有两个关联请求的线程空闲的两个场景:
- 线程需要在构建响应之前等待一个资源可用或者处理数据。例如,一个应用程序需要在构建响应前查询数据库或者通过远程web服务访问数据。
- 线程需要在构建响应之前等待一个事件。例如,线程在构建响应之前需要等待一个JMS消息,另一个客户端的新信息,或者队列里面的新数据可用。
这些场景代表限制web程序可扩展性的阻塞操作。异步处理是指给这些阻塞操作分配一个新线程,并把关联请求处理的线程返回给web容器。
servlet 异步处理
java ee支持servlet和filter的异步处理。如果一个servlet或一个filter处理请求时可能到达一个阻塞操作,它可以把操作分配给一个异步处理上下文并且在不生成响应的情况下将关联请求处理的线程回送给web容器。阻塞操作在不同线程的异步上下文中执行完成,它可以生成响应或者转发请求到另一个servlet。
在一个servlet上启用异步处理,设置@WebServlet注解的asyncSupported参数为true,如下:
@WebServlet(urlPatterns={"/asyncservlet"}, asyncSupported=true) public class AsyncServlet extends HttpServlet { ... }
javax.servlet.AsyncContext类提供在Service方法中执行异步处理所需的功能。获得一个AsyncContext实例,在service方法中调用request对象的startAsync()方法;例如:
public void doGet(HttpServletRequest req, HttpServletResponse resp) { ... AsyncContext acontext = req.startAsync(); ... }
这个调用将请求进入异步模式并且确保响应在退出service方法时每月被提交。你必须在异步上下文完成阻塞操作时生成响应或者转发到其他servlet中。
AsyncContext类提供的基础功能描述:
方法签名:void start(Runnable run)
描述:容器提供的能提供阻塞操作处理的不同线程
方法签名:ServletRequest getRequest()
描述:返回用来初始化异步上下文的请求。在上面的例子中,request与service方法中的相同。你可以通过这个方法在异步上下文中从请求中获取参数。
方法签名:ServletResponse getResponse()
描述:返回初始化异步上下文的响应。在上面的例子中,response与service方法中的相同。你可以在异步上下文中,使用这个方法写入阻塞操作的结果到响应中。
方法签名:void complete()
描述:完成异步操作,并关闭与此异步上下文关联的响应。你可以在异步上下文完成写入响应后调用这个操作。
方法签名:void dispatch(String path)
描述:转发请求和响应到给定的路径。在阻塞操作完成后,使用这个方法调用另一个servlet写出响应。
等待一个资源
这个章节示范了怎么使用AsyncContext上下文提供的功能,有如下用例:
- servlet从一个GET请求中获取参数
- servlet使用一个资源,比如一个数据库或者一个web service,基于这个参数获取信息。这个资源可能比较缓慢,所以这可能是一个阻塞操作。
- servlet使用资源的结果生成响应。
下面的例子是一个不使用异步处理的常见servlet:
@WebServlet(urlPatterns={"/syncservlet"}) public class SyncServlet extends HttpServlet { private MyRemoteResource resource; @Override public void init(ServletConfig config) { resource = MyRemoteResource.create("config1=x,config2=y"); } @Override public void doGet(HttpServletRequest request, HttpServletResponse response) { response.setContentType("text/html;charset=UTF-8"); String param = request.getParameter("param"); String result = resource.process(param); /* ... print to the response ... */ } }
下面的示例是同一个servlet,但使用了异步处理:
@WebServlet(urlPatterns={"/asyncservlet"}, asyncSupported=true) public class AsyncServlet extends HttpServlet { /* ... Same variables and init method as in SyncServlet ... */ @Override public void doGet(HttpServletRequest request, HttpServletResponse response) { response.setContentType("text/html;charset=UTF-8"); final AsyncContext acontext = request.startAsync(); acontext.start(new Runnable() { public void run() { String param = acontext.getRequest().getParameter("param"); String result = resource.process(param); HttpServletResponse response = acontext.getResponse(); /* ... print to the response ... */ acontext.complete(); } }
AsyncServlet在@WebServlet注解属性中添加asyncSupported=true。其余的差异在service方法中:
- request.startAsync() 引发request被异步执行;response不会在service方法结束时发送到客户端;
- acontext.start(new Runnable() {...})从容器中得到一个新的线程。
- 内部类中的run() 中的代码在一个新线程中执行。内部类需要从异步上下文中读取请求参数和写入响应。调用异步上下文的complete()方法来提交并发送响应到客户端。
AsyncServlet的service方法立即返回,同时请求在异步上下文中处理。
以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网
猜你喜欢:- 改进异步封装:处理带返回值的异步调用
- JavaScript | 异步处理
- JavaScript异步处理的那些事儿
- 在 WorkManager 中处理异步任务
- SpringBoot 教程之处理异步请求
- 基于RabbitMQ实现异步消息通知处理
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。