Spring MVC 3.2 預覽:導入 Servlet 3,非同步支援

工程 | Rossen Stoyanchev | 2012 年 5 月 7 日 | ...

上次更新於 2012 年 11 月 5 日 (Spring MVC 3.2 RC1)

總覽

Spring MVC 3.2 導入了基於 Servlet 3 的非同步請求處理。這是關於此新功能的系列文章中的第一篇,提供相關背景知識,以理解如何以及為何使用它。

早期版本的主要目的是徵求意見回饋。自從 3.2 M1 版本發布後,我們已經在這裡和 JIRA 中收到了很多回饋。感謝所有嘗試並發表評論的人!已經有很多變更,而且還有時間提供更多回饋!

概觀

從程式設計模型的角度來看,新功能看起來非常簡單。控制器方法現在可以返回一個 java.util.concurrent.Callable 以非同步完成處理。然後,Spring MVC 將在單獨的執行緒中調用 Callable,並借助 TaskExecutor。這是之前的程式碼片段:


// Before
@RequestMapping(method=RequestMethod.POST)
public String processUpload(final MultipartFile file) {
    // ...
    return "someView";
}

// After
@RequestMapping(method=RequestMethod.POST)
public Callable<String> processUpload(final MultipartFile file) {

  return new Callable<String>() {
    public Object call() throws Exception {
      // ...
      return "someView";
    }
  };
}

控制器方法也可以返回一個 DeferredResult (Spring MVC 3.2 中的新類型) 以在 Spring MVC 未知的執行緒中完成處理。例如,響應 JMS 或 AMQP 消息、Redis 通知等等。這是另一個程式碼片段:


@RequestMapping("/quotes")
@ResponseBody
public DeferredResult<String> quotes() {
  DeferredResult<String> deferredResult = new DeferredResult<String>();
  // Add deferredResult to a Queue or a Map...
  return deferredResult;
}


// In some other thread...
deferredResult.setResult(data);
// Remove deferredResult from the Queue or Map

上面的範例會引發許多問題,我們將在後續文章中詳細介紹。現在,我將首先提供有關這些功能的一些背景知識。

Web 應用程式中非同步的動機

Web 應用程式中非同步的最基本動機是處理需要更長時間才能完成的請求。可能是緩慢的資料庫查詢、對外部 REST API 的呼叫或其他一些 I/O 綁定操作。這種較長的請求會快速耗盡 Servlet 容器的執行緒池並影響擴展性。

在某些情況下,您可以立即返回給客戶端,而後台作業完成處理。例如,發送電子郵件、啟動資料庫作業等,代表著發送後不管的情境,可以使用 Spring 的 @Async 支援或將事件發佈到 Spring Integration 通道來處理,然後返回一個確認 ID,客戶端可以使用該 ID 查詢結果。

在其他需要結果的情況下,我們需要將處理與 Servlet 容器執行緒分離,否則我們將耗盡其執行緒池。Servlet 3 提供了這樣的支援,Servlet (或 Spring MVC 控制器) 可以指示在 Servlet 容器執行緒退出後應保持響應開啟。

為了實現這一點,Servlet 3 Web 應用程式可以調用 request.startAsync() 並使用返回的 AsyncContext 從其他單獨的執行緒繼續寫入響應。同時,從客戶端的角度來看,請求仍然看起來像任何其他 HTTP 請求-響應互動。它只是需要更長的時間才能完成。以下是事件的順序:

  1. 客戶端發送請求
  2. Servlet 容器分配一個執行緒並在其中調用一個 servlet
  3. Servlet 調用 request.startAsync(),保存 AsyncContext,然後返回
  4. 容器執行緒一直退出,但響應保持開啟
  5. 其他一些執行緒使用保存的 AsyncContext 來完成響應
  6. 客戶端收到響應

Servlet 非同步支援當然還有很多內容。您可以找到各種 範例文章,但以上總結了您需要知道的基本、最小的概念。下一篇文章涵蓋了非同步請求處理的第二個動機——瀏覽器需要即時接收信息更新。

獲取 Spring 新聞快訊

隨時關注 Spring 新聞快訊

訂閱

搶先一步

VMware 提供培訓和認證,以加速您的進度。

了解更多

獲得支援

Tanzu Spring 在一個簡單的訂閱中提供 OpenJDK™、Spring 和 Apache Tomcat® 的支援和二進位檔案。

了解更多

即將舉辦的活動

查看 Spring 社群中所有即將舉辦的活動。

查看所有