在Servlet组件接收到的每个请求都会产生一个线程来处理请求并返回响应,当客户端的请求处理是一项比较耗时的过程,当有大量用户请求此Servlet时,Web容器中就会产生大量的线程,导致Web容器性能急剧下降。为了解决这一问题,Servlet提供了对请求的异步处理支持。
异步处理请求的过程为:当Servlet接收到请求之后,首先需要对请求携带的数据进行一些预处理;接着,Servlet线程将请求转交给一个异步线程来执行业务处理,线程本身则返回至容器并可以处理其它客户端的请求,此时Servlet并没有差生响应数据,异步处理完业务以后,可以直接生成响应数据,或者将请求继续转发给其它Servlet。这样,Servlet线程不再是一直处于阻塞状态以等待业务逻辑的处理,而是启动异步线程之后可以立即返回。
使用异步处理,必须要配置相应的部署文件,在web.xml中通过使用<async-supported>标签设置是否需要启用异步处理支持,true表示支持,false表示不支持。当然我们也可以用注解的方式来替代在web.xml中的配置。注解则需要使用asyncSupported属性来支持异步处理。
下面我们看一个小Demo来掩饰Servlet组件的异步处理特性:
package com.yl.servlet; import java.io.IOException; import java.io.PrintWriter; import java.util.Date; import javax.servlet.AsyncContext; import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; /** * Servlet组件异步处理请求特性的演示小程序 * * @author LYYL * */ //通过注解的方式配置,支持异步处理请求 @WebServlet(name="servlet", urlPatterns={"/asyncServlet"}, asyncSupported=true) public class AsyncServlet extends HttpServlet{ @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { processRequest(req, resp); } @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { processRequest(req, resp); } protected void processRequest(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException{ response.setContentType("text/html;charset=UTF-8"); PrintWriter pw = response.getWriter(); pw.println("进入Servlet的时间是:" + new Date() + "."); pw.flush(); //在子线程中执行业务逻辑,并由其负责输出响应,主线程退出 AsyncContext act = request.startAsync(); //创建一个模拟业务逻辑执行的线程 Executor ec = new Executor(act); Thread td = new Thread(ec); td.start(); pw.println("<br>"); pw.println("结束Servlet的时间是: " + new Date() + "."); pw.flush(); } /** * 内部类,模拟线程执行的业务逻辑 * * @author LYYL * */ public class Executor implements Runnable{ private AsyncContext act = null; /** * @param act */ public Executor(AsyncContext act) { this.act = act; } @Override public void run() { try { Thread.sleep(3000); PrintWriter pw = act.getResponse().getWriter(); pw.println("<br>"); pw.println("业务执行完的时间是: " + new Date() + "."); pw.flush(); act.complete(); pw.close(); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } }
最终效果,Servlet开始和结束时间基本一致,而异步线程结束的时间也就是该Servlet执行完业务逻辑的时间是我们设定的3秒之后,如图:
注意:在通过request得到AsyncContext实例的时候用的是startAsync()方法,而不是request.getAsyncContext(),如果你用的是request.getAsyncContext()得到的实例为空,会在异步线程中报空指针异常。
时间: 2024-10-12 07:44:08