11.4 异步监听器

11.4 异步监听器

为支持Servlet和过滤器配合执行异步操作,Servlet3.0还增加了**AsyncListener接口用于接收异步处理过程中发生事件的通知**。AsyncListener接口定义了如下方法,

onStartAsync方法

当某些事件发生时调用:

1
void onStartAsync(AsyncEvent event)

onComplete方法

在异步操作启动完毕后调用该方法。

1
void onComplete(AsyncEvent event)

onError方法

在异步操作失败后调用该方法。

1
void onError(AsyncEvent event)

onTimeout方法

1
void onTimeout(AsyncEvent event)

获取相关的AsyncEvent

在异步操作超时后调用该方法,即当它未能在指定的超时时间内完成时。
所有四种方法可以分别通过它们的getAsyncContextgetSuppliedRequestgetSuppliedResponse方法,从AsyncContextServletRequestServletResponse中获取相关的AsyncEvent

实例

这里有一个例子,MyAsyncListener类实现AsyncListener接口,以便在异步操作事件发生时,它能够得到通知。请注意,和其他网络监听器不同,你不需要通过@WebListener注解来实现。

MyAsyncListener.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
package listener;
import java.io.IOException;
import javax.servlet.AsyncEvent;
import javax.servlet.AsyncListener;
// 不需要标注@WebListener
public class MyAsyncListener
implements
AsyncListener
{
@Override
public void onComplete(AsyncEvent asyncEvent)
throws IOException
{
System.out.println("onComplete");
}
@Override
public void onError(AsyncEvent asyncEvent)
throws IOException
{
System.out.println("onError");
}
@Override
public void onStartAsync(AsyncEvent asyncEvent)
throws IOException
{
System.out.println("onStartAsync");
}
@Override
public void onTimeout(AsyncEvent asyncEvent)
throws IOException
{
System.out.println("onTimeout");
}
}

由于AsyncListener类不是用@WebListener注解的,因此必须为AsyncContext手动注册一个AsyncListener监听器,用于接收所需要的事件。通过调用addListener方法为AsyncContext注册一个AsyncListener监听器:

1
void addListener(AsyncListener listener)

AsyncListenerServlet.java

AsyncListenerServlet类是一个异步Servlet,它利用监听器MyAsyncListener获取事件通知。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
package servlet;
import java.io.IOException;
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 listener.MyAsyncListener;
@WebServlet(
name = "AsyncListenerServlet",
urlPatterns ={"/asyncListener"},
asyncSupported = true
)
public class AsyncListenerServlet extends HttpServlet
{
private static final long serialVersionUID = 62738L;
@Override
public void doGet(final HttpServletRequest request,
HttpServletResponse response)
throws ServletException,IOException
{
//1.获取AsyncContext对象
final AsyncContext asyncContext = request.startAsync();
//2.设置超时时间
asyncContext.setTimeout(5000);
//设置监听器
asyncContext.addListener(new MyAsyncListener());
//3.启动一个线程来处理耗时任务
asyncContext.start(new Runnable()
{
@Override
public void run()
{
//模拟耗时任务
try {
Thread.sleep(3000);
} catch (InterruptedException e) {}
String greeting = "Hi from listener";
request.setAttribute("greeting", greeting);
//4.转到显示页面
asyncContext.dispatch("/test.jsp");
}
});
}
}

test.jsp

1
2
3
4
5
6
<!DOCTYPE HTML>
<html>
<body>
${greeting}
</body>
</html>

运行效果

你可以通过如下URL调用Servlet
http://localhost:8080/app11a/asyncListener
等待3秒钟后,浏览器显示效果如下:
这里有一张图片
控制台输出:

1
onComplete

这表明该异步Servlet结束了

模拟超时

现在修改sleep的时间,如下:

1
2
3
4
//模拟耗时任务
try {
Thread.sleep(6000);
} catch (InterruptedException e) {}

6秒钟比超时时间5秒长,该异步Servlet将会超时.
浏览器显示效果:
这里有一张图片
控制台输出如下:

1
2
3
4
onTimeout
onComplete
Exception in thread "http-nio-8080-exec-28"
......