非同步處理是非常有用的功能,許多時候能帶來很好的體驗。
在Servlet中經常需要調用業務方法,在進行業務處理的時候,Servlet需要等待資料返回後才能繼續往下執行,使得Servlet被阻塞。當然,處理這些比較耗時的業務的時候,可以啟動另外的線程去處理,然後Servlet繼續往下執行,但是啟動的這個業務處理線程是沒有辦法和用戶端互動的,只是在伺服器端執行,不能主動的向用戶端發送處理資訊。
Servlet3.0通過進入非同步處理,使得Servlet調用業務方法的時候不被阻塞,而是直接返回。非同步處理的上下文AsyncContext負責管理執行完業務方法後的回應,AsyncContext決定該回應是應該被原來的線程處理還是應該分發給容器中其他的資源。
要使用Servlet3.0的非同步處理,需要設定@WebServlet的屬性asyncSupported=true,預設是false。如果配置了過濾器,也需要設定@WebFilter的屬性asyncSupported=true。
一個簡單的非同步處理Servlet:
package com.cndatacom.servlet;import java.io.IOException;import java.io.PrintWriter;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 com.cndatacom.thread.BusinessHandleThread;/** * 非同步處理Servlet * @author Luxh *//** * asyncSupported屬性預設是false,如果需要開啟支援非同步處理功能,需要設定為true */@WebServlet(name="AsyncServlet",urlPatterns="/AsyncServlet",asyncSupported=true)public class AsyncServlet extends HttpServlet{@Overrideprotected void doGet(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException { response.setCharacterEncoding("utf-8");response.setContentType("text/html;charset=utf-8");PrintWriter out = response.getWriter();out.println("Servlet begin <br>");//進入非同步模式,調用業務處理線程進行業務處理//Servlet不會被阻塞,而是直接往下執行//業務處理完成後的回應由AsyncContext管理AsyncContext asyncContext = request.startAsync();BusinessHandleThread businessHandleThread = new BusinessHandleThread(asyncContext);Thread thread = new Thread(businessHandleThread);thread.start(); //asyncContext.start(businessHandleThread);//也可以用這種方法啟動非同步線程out.println("Servlet end <br>");out.flush();}}
進行業務處理的線程:
package com.cndatacom.thread;import java.io.PrintWriter;import javax.servlet.AsyncContext;import javax.servlet.ServletResponse;/** * 業務處理線程 * @author Luxh */public class BusinessHandleThread implements Runnable {//非同步作業的內容物件,通過構造方法傳進來private AsyncContext asyncContext;public BusinessHandleThread(AsyncContext asyncContext) {this.asyncContext =asyncContext;}@Overridepublic void run() {try {//do some work...Thread.sleep(6000);ServletResponse response = asyncContext.getResponse();PrintWriter out = response.getWriter();out.println("業務處理方法執行結束");//這句話會響應到用戶端//告訴啟動非同步處理的Servlet非同步處理已完成,Servlet就會提交請求asyncContext.complete();} catch (Exception e) {e.printStackTrace();}}}
AsyncContext:代表的是一個ServletRequest發起一個非同步作業的執行內容。
使用request.startAsync()方法擷取AsyncContext。startAsync()不帶參數是直接採用Servlet容器傳過來的Request和Response。如果Servlet沒有標明支援要求的非同步處理,那麼調用這個方法會拋出IllegalStateException。
在處理線程中調用asyncContext.complete()方法來完成非同步處理的調用,啟動非同步處理的Servlet就會提交請求。