iT邦幫忙

1

【左京淳的JAVA WEB學習筆記】第八章 伺服器異步設定

在特定時間開放搶票的網站,常常會有流量爆炸的問題。這時候可以透過伺服器的異步處理來解決。
讓買票處理使用主線程,而需要等待的出票處理使用異步線程。
要使用異步線程,需在Servlet前註解支持異步處理。然後利用request物件叫出AsyncContext物件。
這時response回應就會等到AsyncContext.complete()結束時才被送出。關鍵程式碼如下:

@WebServlet(urlPatterns="/AsynSvl",asyncSupported=true)
AsyncContext ac = request.startAsync();
ServletResponse res = ac.getResponse();

新建一個測試案例

  1. asynTest.jsp
"<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>"
(餘略…)
  1. AsynSvl
@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"字樣

異步監聽器

利用異步監聽器可以檢測異步處理的執行狀況。監聽器可能會收到以下幾種結果,可以設定相應的處理:

  • onStartAsync //AsyncContext重新創建時觸發此方法
  • onComplete //正常結束時觸發此方法
  • onTimeout //超時的時候觸發此方法,默認為30秒,也可利用setTimeout()自行設定。
  • onError //錯誤時觸發此方法

修改剛才的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。


尚未有邦友留言

立即登入留言