知識庫 / Spring WebFlux RSS 訂閱

Spring MVC 異步處理 vs Spring WebFlux

Spring MVC,Spring WebFlux
HongKong
10
12:48 PM · Dec 06 ,2025

1. 引言

在本教程中,我們將探討 Spring MVC 中 <em @Async</em> 註解,並隨後熟悉 Spring WebFlux。 我們的目標是更好地理解這兩種技術的區別。

2. 實施場景

這裏,我們將選擇一個場景來展示如何使用這些 API 實現一個簡單的 Web 應用程序。我們尤其感興趣的是在每種情況下,瞭解線程管理和阻塞或非阻塞 I/O 的更多信息。

讓我們選擇一個具有一個返回字符串結果的端點的 Web 應用程序。這裏的關鍵在於,請求將通過一個 Filter,延遲 200 毫秒,然後 Controller 需要 500 毫秒來計算並返回結果。

接下來,我們將使用 Apache ab 在兩個端點上模擬負載,並使用 JConsole 監控應用程序的行為。

值得一提的是,在本文中,我們的目標不是對這兩個 API 進行基準測試,而只是一個小規模的負載測試,以便我們能夠跟蹤線程管理

3. Spring MVC 異步處理

Spring 3.0 引入了 @Async 註解。 @Async 的目標是允許應用程序在單獨的線程上運行高負載的任務。 調用者也可以在感興趣時等待結果。 因此,返回值不能為 void, 必須是 FutureCompletableFutureListenableFuture 中的一種。

此外,Spring 3.2 引入了 org.springframework.web.context.request.async 包,與 Servlet 3.0 一起,將異步處理的樂趣帶到了 Web 層。

因此,自 Spring 3.2 以來,@Async 可以用於標記為 @Controller@RestController 的類。

當客户端發起請求時,請求會經過過濾器鏈中所有匹配的過濾器,直到到達 DispatcherServlet 實例。

然後,servlet 負責異步調度請求。 它通過調用 AsyncWebRequest#startAsync 開始請求,將請求處理任務轉移到 WebSyncManager 實例,並在不提交響應的情況下完成任務。 過濾器鏈也以相反的方向遍歷到根目錄。

WebAsyncManager 將請求處理任務提交到其關聯的 ExecutorService

4. Spring Async 實現

讓我們通過編寫我們的應用程序類 AsyncVsWebFluxApp 開始實現。 @EnableAsync 負責為我們的 Spring Boot 應用程序啓用異步功能:

@SpringBootApplication
@EnableAsync
public class AsyncVsWebFluxApp {
    public static void main(String[] args) {
        SpringApplication.run(AsyncVsWebFluxApp.class, args);
    }
}

然後我們有 AsyncFilter, 它實現了 javax.servlet.Filter。請記住在 doFilter 方法中模擬延遲:

@Component
public class AsyncFilter implements Filter {
    ...
    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain)
      throws IOException, ServletException {
        // sleep for 200ms 
        filterChain.doFilter(servletRequest, servletResponse);
    }
}

最後,我們使用“/async_result”端點開發了我們的 AsyncController

@RestController
public class AsyncController {
    @GetMapping("/async_result")
    @Async
    public CompletableFuture getResultAsyc(HttpServletRequest request) {
        // sleep for 500 ms
        return CompletableFuture.completedFuture("Result is ready!");
    }
}

由於上述的 @Async,該方法將在應用程序的默認 ExecutorService 中以一個單獨的線程執行。但是,為了我們的方法,也可以設置一個特定的 ExecutorService

測試時間!讓我們運行應用程序,安裝 Apache ab,或者任何工具來模擬負載。然後我們可以向“async_result”端點發送大量的併發請求。我們可以執行 JConsole 並將其附加到我們的 Java 應用程序以監控進程:

ab -n 1600 -c 40 localhost:8080/async_result

 

5. Spring WebFlux

Spring 5.0 引入了 WebFlux 以非阻塞方式支持響應式 Web。WebFlux 基於 Reactor API,是 響應式流 的又一種出色實現。

WebFlux 支持響應式背壓以及 Servlet 3.1+,並利用其非阻塞 I/O。因此,它可以運行在 Netty、Undertow、Jetty、Tomcat 或任何 Servlet 3.1+ 兼容服務器上。

雖然所有服務器不使用相同的線程管理和併發控制模型,但只要它們支持非阻塞 I/O 和響應式背壓,WebFlux 就能正常工作。

WebFlux 允許我們以聲明式的方式分解邏輯,使用 Mono, Flux 以及它們豐富的操作符集。 此外,我們還可以擁有除了帶有 @Controller 註解的端點之外的其他功能性端點,儘管我們現在也可以在 Spring MVC 中使用它們。

6. Spring WebFlux 實現

為了實現 WebFlux,我們遵循異步編程的路徑。首先,我們創建 AsyncVsWebFluxApp

@SpringBootApplication
public class AsyncVsWebFluxApp {
    public static void main(String[] args) {
        SpringApplication.run(AsyncVsWebFluxApp.class, args);
    }
}

然後我們來編寫我們的 WebFluxFilter,它實現了 WebFilter。 我們將生成一個人為的延遲,然後將請求傳遞到過濾器鏈中:

@Component
public class WebFluxFilter implements org.springframework.web.server.WebFilter {

    @Override
    public Mono filter(ServerWebExchange serverWebExchange, WebFilterChain webFilterChain) {
        return Mono
          .delay(Duration.ofMillis(200))
          .then(
            webFilterChain.filter(serverWebExchange)
          );
    }
}

最後,我們擁有了 WebFluxController。它暴露了一個名為 “/flux_result” 的端點,並返回一個 Mono<String> 作為響應:

@RestController
public class WebFluxController {

    @GetMapping("/flux_result")
    public Mono getResult(ServerHttpRequest request) {
       return Mono.defer(() -> Mono.just("Result is ready!"))
         .delaySubscription(Duration.ofMillis(500));
    }
}

對於本次測試,我們採用與異步示例應用程序相同的策略。以下是示例結果:

ab -n 1600 -c 40 localhost:8080/flux_result

7. 區別分析

Spring Async 支持 Servlet 3.0 規範,而 Spring WebFlux 支持 Servlet 3.1+。 這帶來了一系列差異:

  • Spring Async 在與客户端通信期間採用阻塞式 I/O 模型,可能導致與慢速客户端的性能問題。 相反,Spring WebFlux 提供非阻塞式 I/O 模型。
  • 在 Spring Async 中,讀取請求體或請求部分是阻塞操作,而在 Spring WebFlux 中則是非阻塞操作。
  • 在 Spring Async 中,FilterServlet 是同步工作,而 Spring WebFlux 支持完整的異步通信。
  • Spring WebFlux 與 Spring Async 兼容的 Web/Application 服務器範圍更廣,例如 Netty 和 Undertow。

此外,Spring WebFlux 支持 reactive backpressure,因此我們對快速生產者如何響應擁有更多的控制,優於 Spring MVC Async 和 Spring MVC。

Spring WebFlux 還通過 Reactor API 推動了編程風格向函數式編程的轉變,以及聲明式 API 分解。

所有這些因素是否會導致我們使用 Spring WebFlux? 答案是:Spring Async 甚至 Spring MVC 可能會是許多項目中正確的選擇,具體取決於系統的負載可伸縮性和可用性。

在可伸縮性方面,Spring Async 的結果優於同步的 Spring MVC 實現。 Spring WebFlux,由於其反應式特性,為我們提供了彈性以及更高的可用性。

8. 結論

在本文中,我們更深入地瞭解了 Spring Async 和 Spring WebFlux,並通過一個基本的負載測試,對它們進行了理論和實踐上的比較。

user avatar
0 位用戶收藏了這個故事!
收藏

發佈 評論

Some HTML is okay.