在特定時間開放搶票的網站,常常會有流量爆炸的問題。這時候可以透過伺服器的異步處理來解決。
讓買票處理使用主線程,而需要等待的出票處理使用異步線程。
要使用異步線程,需在Servlet前註解支持異步處理。然後利用request物件叫出AsyncContext物件。
這時response回應就會等到AsyncContext.complete()結束時才被送出。關鍵程式碼如下:
@WebServlet(urlPatterns="/AsynSvl",asyncSupported=true)
AsyncContext ac = request.startAsync();
ServletResponse res = ac.getResponse();
新建一個測試案例
"<body>
<input type=""button"" value=""測試"" onclick=""submit()""><br>
<span id=""info"" style=""color:red;font-size:12px""></span>
</body>"
"<%
String path = request.getContextPath();
String basePath = request.getScheme() + ""://"" + request.getServerName()
+ "":"" + request.getServerPort() + path + ""/"";
%><script src=""http://ajax.microsoft.com/ajax/jQuery/jquery-1.4.4.min.js""></script>
<script type=""text/javascript"">
function submit(){
var url = ""<%=basePath%>AsynSvl"";
$.ajax({
type:""get"",
url:url,
success:function(msg){
document.getElementById(""info"").innerHTML=msg;
}
})
}
</script>"
(餘略…)
@WebServlet(urlPatterns="/AsynSvl",asyncSupported=true)
public class AsynSvl extends HttpServlet {
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
AsyncContext ac = request.startAsync();
ServletResponse res = ac.getResponse();
res.setCharacterEncoding("utf-8");
PrintWriter out = res.getWriter();
try {
Thread.sleep(3000);
}catch(Exception e){
}
out.println("異步處理OK");
out.flush();
out.close();
}
(餘略…)
}
如果異步處理的url有經過過濾器(Filter),則過濾器也要設定支持異步。
@WebFilter(urlPatterns = "/*",
asyncSupported=true,
initParams = {@WebInitParam(name = "encoding",value = "utf-8")})
直接拜訪jsp網址,然後點選測試。
http://localhost:8080/Hello/main/asynTest.jsp
成功的話會看到"異步處理OK"字樣
利用異步監聽器可以檢測異步處理的執行狀況。監聽器可能會收到以下幾種結果,可以設定相應的處理:
修改剛才的AsynSvl,在裡面添加一個MyListener類。
public class AsynSvl extends HttpServlet {
class MyListener implements AsyncListeren{
public void onComplete(AsyncEvent e) throws IOException{
System.out.println(e.getAsyncContext().hashCode() + "onComplete");
}
public void onError(AsyncEvent e) throws IOException{
System.out.println(e.getAsyncContext().hashCode() + "onError");
}
public void onStartAsync(AsyncEvent e) throws IOException{
System.out.println(e.getAsyncContext().hashCode() + "onStartAsync");
}
public void onTimeout(AsyncEvent e) throws IOException{
System.out.println(e.getAsyncContext().hashCode() + "onTimeout");
}
}
(中略…)
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
AsyncContext ac = request.startAsync();
ac.addListener(new MyListener());
ServletResponse res = ac.getResponse();
res.setCharacterEncoding("utf-8");
PrintWriter out = res.getWriter();
try {
Thread.sleep(3000);
}catch(Exception e){
}
out.println("異步處理OK");
out.flush();
out.close();
ac.complete();
//ac.setTimeout(5000);
}
}
建立了MyListener類之後別忘了在doGet()裡面添加這行ac.addListener(new MyListener());
不然待會兒測試的時候,腦海中就會響起五月天的聽不到
當執行到ac.complete()時,監聽器會在後台印出onComplete。
如果把這行註解掉,那麼預設等待30秒後,會得到onTimeout及onComplete。
如果註解掉ac.complete()後,再添加ac.setTimeout(5000),則五秒後會得到onTimeout及onComplete。