JavaEE Async 异步支持

前言

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

使用Async的步骤

启用async

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

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

在Servlet中开启async

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
@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内容:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
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接口,该接口需要实现如下方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
@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的时候被调用
}

添加监听器的方法:

1
asyncContext.addListener(new MyAsyncListener);

总结

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

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