1. 程式人生 > >Spring註解開發系列Ⅸ --- 非同步請求

Spring註解開發系列Ⅸ --- 非同步請求

一. Servlet中的非同步請求

在Servlet 3.0之前,Servlet採用Thread-Per-Request的方式處理請求,即每一次Http請求都由某一個執行緒從頭到尾負責處理。如果要處理一些IO操作,以及訪問資料庫,呼叫第三方服務介面時,這種做法是十分耗時的。可以用程式碼測試一下:

同步方式處理: 

@WebServlet("/helloServlet")
public class HelloServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        System.out.println(Thread.currentThread()+"start...");
        try {
            sayHello();
        } catch (InterruptedException e) { e.printStackTrace(); } resp.getWriter().write("hello..."); System.out.println(Thread.currentThread()+" end ...."); } public void sayHello() throws InterruptedException { Thread.sleep(3000); } }

以上程式碼,執行了一個3秒的方法,主執行緒在3秒方法執行完之後,才得到釋放,這樣處理效率非常不高。在Servlet 3.0引入了非同步處理,然後在Servlet 3.1中又引入了非阻塞IO來進一步增強非同步處理的效能。

非同步方式處理業務邏輯:

@WebServlet(value = "/asyncServlet",asyncSupported = true)
public class AsyncHelloServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        System.out.println(Thread.currentThread()+"主執行緒start..."+System.currentTimeMillis());
        //1.支援非同步處理 asyncSupported = true
        //2.開啟非同步
        AsyncContext asyncContext = req.startAsync();
        //3.業務邏輯業務處理
        asyncContext.start(new Runnable() { @Override public void run() { try { System.out.println(Thread.currentThread()+"副執行緒start..."+System.currentTimeMillis()); sayHello(); asyncContext.complete(); //4.獲取響應 ServletResponse response = asyncContext.getResponse(); response.getWriter().write("hello,async..."); System.out.println(Thread.currentThread()+"副執行緒end..."+System.currentTimeMillis()); } catch (InterruptedException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } } }); System.out.println(Thread.currentThread()+"主執行緒end..."+System.currentTimeMillis()); //測試結果,主執行緒接受請求處理,並立即得到釋放,副執行緒處理業務邏輯 /** * Thread[http-apr-8080-exec-9,5,main]主執行緒start...1545911791802 * Thread[http-apr-8080-exec-9,5,main]主執行緒end...1545911791806 * Thread[http-apr-8080-exec-10,5,main]副執行緒start...1545911791806 * Thread[http-apr-8080-exec-10,5,main]副執行緒end...1545911794807 */ } public void sayHello() throws InterruptedException { Thread.sleep(3000); }

上面的程式碼中,主執行緒在Servlet被執行到時,立刻得到了釋放,然後在副執行緒中呼叫了sayHello方法,3秒後副執行緒得到釋放,這就是非同步Servlet最簡單的一個demo演示。