前言

Async技术是Servlet3.0 之后添加的,用于处理异步请求。在此之前,大多为同步请求,客户端向服务器提交请求,假设请求很耗时,那么按照之前同步的处理办法,servlet在接收到这个请求之后,会调用去处理这个耗时操作,如果这个耗时操作长时间没有返回,那么就造成了服务器的阻塞,服务器资源得不到有效利用,这样的结果显然对于服务器的高并发是非常不利的。
服务器可以异步执行,在等待长时间的过程完成期间,控制容器执行其他任务,当耗时操作完成返回后,再调用资源处理这个返回请求。

使用Async的步骤

启用async

异步行为需要在Servlet中显式启用 ,其方法有两种:

  • 添加@WebServlet的**asyncSupported**属性实现
@WebServlet(urlPatterns = "/async", asyncSupported = true)
  • 在**web.xml**文件中实现
    <servlet>
        <servlet-name>AsyncServlet</servlet-name>
        <servlet-class>com.dimple.servlet.AsyncServlet</servlet-class>
        <async-supported>true</async-supported> <!--设置启用Async-->
    </servlet>

在Servlet中开启async

@WebServlet(name = "AsyncServlet", urlPatterns = "/async",asyncSupported = true)
public class AsyncServlet extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doGet(request, response);
    }

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        PrintWriter out = response.getWriter();
        //输出Servlet开始的时候的系统时间
        out.println("Servlet is starting:"+new Date());
        //创建AsyncContext,开始异步调用
        AsyncContext asyncContext=request.startAsync();
        //设置超时时长,单位为毫秒
        asyncContext.setTimeout(60*1000);
        //启动异步调用的线程
        asyncContext.start(new MyTask(asyncContext));
        //输出Servlet结束的时间
        out.println("Servlet is ending :"+new Date());
    }
}

MyTask内容:

public class MyTask implements Runnable {
    AsyncContext context;

    public MyTask(AsyncContext context) {
        this.context = context;
    }

    /**
     * 此处单开一个线程进行耗时操作,为了模拟耗时操作,这里先让线程Sleep5秒。
     */
    @Override
    public void run() {
        try {
            Thread.sleep(5*1000);
            context.getResponse().getWriter().print("async is ending : "+new Date());
        } catch (InterruptedException | IOException e) {
            e.printStackTrace();
        }
    }
}

执行结果如下:

这里写图片描述

注意:这是采用IDEA开发的,可能采用Eclipse的小伙伴的开发的和我这边的url不一样。

AsyncListener 异步监听器

为了更加清晰的看到异步操作的各种细节,可以借助异步监听器实现。
异步监听器需要实现AsyncListener接口,该接口需要实现如下方法:

            @Override
            public void onComplete(AsyncEvent asyncEvent) throws IOException {
                //当异步调用完成后被调用
            }

            @Override
            public void onTimeout(AsyncEvent asyncEvent) throws IOException {
                //超时被调用
            }

            @Override
            public void onError(AsyncEvent asyncEvent) throws IOException {
                //出现错误的时候被调用
            }

            @Override
            public void onStartAsync(AsyncEvent asyncEvent) throws IOException {
                //启动Async的时候被调用
            }

添加监听器的方法:

asyncContext.addListener(new MyAsyncListener);

总结

使用Servlet3.0的Async异步支持,步骤总结如下:

  • 首先先声明异步支持(web.xml或者注解@webServlet)
  • 在相应的Servlet中获取AsyncContext实例。一般采用request.startAsync();该方法发挥一个AsyncContext对象。
  • 设置超时context.setTimeout();
  • 启动线程context.start(Runable runable);
  • 在相应的实现Runable接口的方法里进行耗时操作。