在早前版本的Servlet規範中,若是Servlet做爲控制器調用了一個較耗時的業務方法,那麼Servlet必須等到業務方法徹底返回以後才生成響應,這使得Servlet對業務方法的調用變成一種阻塞式的調用,從而致使運行效率下降。 html
Servlet3.0規範引入了異步處理來解決這個問題,異步處理容許Servlet從新發起一條新線程去調用較耗時的業務方法,這樣就可避免等待。該異步機制是經過AsyncContext類來處理的,Servlet可經過ServletRequest的以下兩個方法開啓異步調用、建立AsyncContext對象: java
一、AsyncContext startAsync() session
二、AsyncContext startAsync(ServletRequest,ServletResponse) 異步
重複調用上面的方法將獲得同一個AyncContext對象,AyncContext對象表明異步處理的上下文,它提供了一些工具方法,能夠完成設置異步調用的超時時長,dispatch用於請求,啓動後臺線程、獲取request response對象等功能 jsp
Code demo: async
@WebServlet(urlPatterns="/async",asyncSupported=true) ide
public class AsyncServlet extends HttpServlet 工具
{ this
@Override url
public void doGet(HttpServletRequest request,HttpServletResponse response)throws IOException,ServletException{
response.setContentType("text/html,charset=GBK");
PrinterWriter out = response.getWriter();
out.println("<title>異步</tilte>");
out.println("進入Servlet的時間:"+new java.util.Date()+".<br/>");
out.flush();
// 建立AsyncContext,開始異步調用
AsyncContext actx = request.startAsync();
// 設置異步調用的超時時長
actx.setTimeout(30*1000);
// 啓動異步調用的線程
actx.start(new Executor(actx));
out.println("結束Servlet的時間:"+new java.util.Date()+".<br />");
out.flush();
}
}
Excutor.java:
public class Executor implements Runnable
{
pirvate AyncContext actx = null;
public Executor(AsyncContext){ this.actx = actx; }
public void run()
{
try{
// 等待10秒,模擬業務方法的執行
Thread.sleep(10 * 1000);
ServletRequest request = actx.getRequest();
List<String> books = new ArrayList<>();
books.add("Thinking in java");
books.add("Effective java");
books.add("Core Java");
request.setAttribute("books",books);
actx.dispatch("/async.jsp");
}catch(Exception e){ e.printStackTrace(); }
}
}
該線程執行體內讓線程暫停10秒鐘來模擬調用耗時的業務方法,最後調用 AsyncContext的dispatch方法把請求dispatch到指定的JSP頁面。
被 異步請求dispatch的目標頁面須要指定session="false",代表該頁面不會從新建立 session。
async.jsp:
<% page contentType="text/html;charset=GBK" language="java" session="false"%>
<% taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<ul>
<c:forEach items="${books}" var ="book">
<li>${book}</li>
</c:forEach>
</ul>
<%
out.println("調用業務結束時間:"+new java.util.Date());
request.getAsyncContext().complete();
%>