servlet3.0规范中添加了异步处理,即一部分操作处理完成之后,先行把数据返回来,对于另一部分比较耗时的操作可以放置到另外一个线程中进行处理,该线程保留有连接的请求和响应对象,在处理完成之后可以把处理的结果通知到客户端,实例代码如下:
1. import java.io.IOException;
2. import java.io.PrintWriter;
3. import java.util.Date;
4.
5. import javax.servlet.AsyncContext;
6. import javax.servlet.AsyncEvent;
7. import javax.servlet.AsyncListener;
8. import javax.servlet.ServletException;
9. import javax.servlet.annotation.WebServlet;
10. import javax.servlet.http.HttpServlet;
11. import javax.servlet.http.HttpServletRequest;
12. import javax.servlet.http.HttpServletResponse;
13.
14. /**
15. * @Title: AsynServlet.java
16. * @Package
17. * @Description: TODO
18. * @author ynb
19. * @date 2014-7-24 下午5:07:00
20. * @version V1.0
21. */
22.
23. /**
24. * @author admin
25. *
26. */
27. @WebServlet(urlPatterns="/demo", asyncSupported=true)
28. public class AsynServlet extends HttpServlet {
29. private static final long serialVersionUID = -8016328059808092454L;
30.
31. /* (non-Javadoc)
32. * @see javax.servlet.http.HttpServlet#service(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse)
33. */
34. @Override
35. protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
36. "text/html;charset=UTF-8");
37. PrintWriter out = resp.getWriter();
38. "进入Servlet的时间:" + new Date() + ".");
39. out.flush();
40.
41. //在子线程中执行业务调用,并由其负责输出响应,主线程退出
42. final AsyncContext ctx = req.startAsync();
43. 200000);
44. new Work(ctx).start();
45. "结束Servlet的时间:" + new Date() + ".");
46. out.flush();
47. }
48. }
49.
50. class Work extends Thread{
51. private AsyncContext context;
52.
53. public Work(AsyncContext context){
54. this.context = context;
55. }
56. @Override
57. public void run() {
58. try {
59. 2000);//让线程休眠2s钟模拟超时操作
60. PrintWriter wirter = context.getResponse().getWriter();
61. "延迟输出");
62. wirter.flush();
63. context.complete();
64. catch (InterruptedException e) {
65.
66. catch (IOException e) {
67.
68. }
69. }
70. }
有些时候,我们可能需要客户端和服务器保持长连接的时候,我们可以使用这个特性,让服务器长时间保持客户端的请求以及对客户端的响应,做法如下:
对于异步执行,我们可以添加一个监听器,监听异步执行的状态。
1. ctx.addListener(new AsyncListener() {
2. @Override
3. public void onTimeout(AsyncEvent arg0) throws IOException {
4. // TODO Auto-generated method stub
5.
6. }
7.
8. @Override
9. public void onStartAsync(AsyncEvent arg0) throws IOException {
10. // TODO Auto-generated method stub
11.
12. }
13.
14. @Override
15. public void onError(AsyncEvent arg0) throws IOException {
16. // TODO Auto-generated method stub
17.
18. }
19.
20. @Override
21. public void onComplete(AsyncEvent arg0) throws IOException {
22. // TODO Auto-generated method stub
23.
24. }
25. );
在Servlet返回之前,我们可以把持有request和response对象的AsyncContext对象放置到一个全局可访问的静态容器中
1. map.put("id",ctx);
如果连接出错或者连接完的时候我们可以在onError以及onComplete方法中移除掉对应连接的AsyncContext
1. map.remove("id",ctx);
在超时的回调方法onTimeout中,我们可以往浏览器发送指定的信息,让客户端重新发起请求,这样就可以保持客户端和服务器的长久连接。
如下服务器和客户端之间数据交互的模型图