异步处理是非常有用的功能,许多时候能带来很好的体验。
在Servlet中经常需要调用业务方法,在进行业务处理的时候,Servlet需要等待数据返回后才能继续往下执行,使得Servlet被阻塞。当然,处理这些比较耗时的业务的时候,可以启动另外的线程去处理,然后Servlet继续往下执行,但是启动的这个业务处理线程是没有办法和客户端交互的,只是在服务器端执行,不能主动的向客户端发送处理信息。
Servlet3.0通过进入异步处理,使得Servlet调用业务方法的时候不被阻塞,而是直接返回。异步处理的上下文AsyncContext负责管理执行完业务方法后的回应,AsyncContext决定该回应是应该被原来的线程处理还是应该分发给容器中其他的资源。
要使用Servlet3.0的异步处理,需要设置@WebServlet的属性asyncSupported=true,默认是false。如果配置了过滤器,也需要设置@WebFilter的属性asyncSupported=true。
一个简单的异步处理Servlet:
package com.cndatacom.servlet; import java.io.IOException; import java.io.PrintWriter; 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; import com.cndatacom.thread.BusinessHandleThread; /** * 异步处理Servlet * @author Luxh */ /** * asyncSupported属性默认是false,如果需要开启支持异步处理功能,需要设置为true */ @WebServlet(name="AsyncServlet",urlPatterns="/AsyncServlet",asyncSupported=true) public class AsyncServlet extends HttpServlet{ @Override protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { response.setCharacterEncoding("utf-8"); response.setContentType("text/html;charset=utf-8"); PrintWriter out = response.getWriter(); out.println("Servlet begin <br>"); //进入异步模式,调用业务处理线程进行业务处理 //Servlet不会被阻塞,而是直接往下执行 //业务处理完成后的回应由AsyncContext管理 AsyncContext asyncContext = request.startAsync(); BusinessHandleThread businessHandleThread = new BusinessHandleThread(asyncContext); Thread thread = new Thread(businessHandleThread); thread.start(); //asyncContext.start(businessHandleThread);//也可以用这种方法启动异步线程 out.println("Servlet end <br>"); out.flush(); } }
进行业务处理的线程:
package com.cndatacom.thread; import java.io.PrintWriter; import javax.servlet.AsyncContext; import javax.servlet.ServletResponse; /** * 业务处理线程 * @author Luxh */ public class BusinessHandleThread implements Runnable { //异步操作的上下文对象,通过构造方法传进来 private AsyncContext asyncContext; public BusinessHandleThread(AsyncContext asyncContext) { this.asyncContext =asyncContext; } @Override public void run() { try { //do some work... Thread.sleep(6000); ServletResponse response = asyncContext.getResponse(); PrintWriter out = response.getWriter(); out.println("业务处理方法执行结束");//这句话会响应到客户端 //告诉启动异步处理的Servlet异步处理已完成,Servlet就会提交请求 asyncContext.complete(); } catch (Exception e) { e.printStackTrace(); } } }
AsyncContext:代表的是一个ServletRequest发起一个异步操作的执行上下文。
使用request.startAsync()方法获取AsyncContext。startAsync()不带参数是直接采用Servlet容器传过来的Request和Response。如果Servlet没有标明支持请求的异步处理,那么调用这个方法会抛出IllegalStateException。
在处理线程中调用asyncContext.complete()方法来完成异步处理的调用,启动异步处理的Servlet就会提交请求。