領先一步
VMware 提供培訓和認證,助您加速進步。
瞭解更多最後更新於 2012 年 11 月 5 日 (Spring MVC 3.2 RC1)
概述
Spring MVC 3.2 引入了基於 Servlet 3 的非同步請求處理。這是涵蓋此新功能的多篇博文中的第一篇,並提供了理解如何以及為何使用它的背景。
早期釋出的主要目的是尋求反饋。自 3.2 M1 版本釋出以來,我們在這裡和 JIRA 中收到了大量反饋。感謝所有嘗試並發表評論的人!有無數的更改,還有時間接受更多反饋!
一覽
從程式設計模型角度來看,新功能看似非常簡單。控制器方法現在可以返回一個 java.util.concurrent.Callable 以非同步完成處理。然後,Spring MVC 將在 TaskExecutor 的幫助下,在一個單獨的執行緒中呼叫 Callable。這是一段之前的程式碼片段。
// 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容器的執行緒池,影響可伸縮性。
在某些情況下,您可以在後臺作業完成處理的同時立即返回給客戶端。例如,傳送電子郵件、啟動資料庫作業以及其他“即發即棄”(fire-and-forget)場景,這些可以透過Spring的 @Async 支援,或者透過將事件釋出到 Spring Integration 通道來處理,然後返回一個客戶端可以使用該確認ID來查詢結果。
在其他需要結果的情況下,我們需要將處理與Servlet容器執行緒解耦,否則我們將耗盡其執行緒池。Servlet 3提供了這樣的支援,其中Servlet(或Spring MVC控制器)可以在Servlet容器執行緒退出後指示響應保持開啟狀態。
為了實現這一點,Servlet 3 Web應用程式可以呼叫 request.startAsync() 並使用返回的 AsyncContext 從其他獨立執行緒繼續寫入響應。同時,從客戶端的角度來看,請求仍然像任何其他HTTP請求-響應互動一樣。只是完成需要更長時間。以下是事件序列:
request.startAsync(),儲存 AsyncContext,然後返回AsyncContext 完成響應當然,Servlet非同步支援還有很多內容。您可以找到 各種 示例 和 文件,但以上總結了您需要了解的基本、最低概念。 下一篇博文 將介紹非同步請求處理的第二個動機——瀏覽器接收即時資訊更新的需求。