淺談Spring 5的響應式編程

這篇使用Spring 5進行響應式編程的入門文章展現了你如今能夠使用的一些新的non-blocking, asynchronous。感謝優銳課老師給予的指導!java

近年來,因爲響應式編程可以以聲明性的方式(而不是強制性的)構建應用程序,從而在響應程序和彈性方面具備更強的響應能力,所以在開發人員社區和客戶中日益流行。Spring 5將Reactive Systems歸入其核心框架的事實代表,範式已向聲明式編程轉移。react

響應式編程管理數據生產者與須要以非阻塞方式對數據作出反應的使用者之間的異步數據流。所以,響應式編程所有與異步和事件驅動的非阻塞應用程序有關,這些應用程序須要少許線程來擴展。web

因爲基於共享的可變狀態,線程和鎖擴展應用程序存在很高的複雜性,所以很難使用基於線程的框架來構建反應性應用程序。算法

在響應式編程上下文中,「一切都是流,而且當流中有數據時,一切都以非阻塞的方式進行。」spring

 

爲何響應式編程

響應式編程的高度抽象性提升了代碼的可讀性,所以開發人員能夠主要關注定義業務邏輯的事件的相互依賴性。數據庫

反應模式天然適合高度併發環境中的消息處理,這是企業常見的用例。編程

具備強制背壓的功能,響應式方法最適合控制生產者和消費者之間的流量,這將有助於避免內存不足的問題。架構

響應式編程能夠更有效地管理高度互動和實時的應用程序或任何動做/事件可能觸發多個鏈接子系統的通知的狀況。併發

 

實現響應式編程的理想用例

  • 大量交易處理服務,例如銀行業。
  • 大型在線購物應用程序(例如Amazon)的通知服務。
  • 股票交易同時變化的股票交易業務。

響應式流

「響應流」定義了一個API規範,該規範包含一組最少的接口,這些接口公開了用於定義具備非阻塞背壓的異步數據流的操做和實體的方法。mvc

引入反壓後,反應流容許訂戶控制發佈者的數據交換速率。

Reactive Streams API做爲java.util.concurrent.Flow正式成爲Java 9的一部分。

響應式流主要用做互操做性層。

 

Spring 5響應式編程產品

Spring-Web-Reactive模塊和Spring MVC都支持相同的@Controller編程,可是Spring-Web-Reactive另外在Reactive和非阻塞引擎上執行。

Spring-Web-Reactive模塊和Spring MVC共享許多經常使用算法,可是Spring-Web-Reactive模塊已經從新定義了許多Spring MVC合約,例如HandlerMapping和HandlerAdapter,以使它們異步和非阻塞並啓用 反應性HTTP請求和響應(以RouterFunction和HandlerFunction的形式)。

除了現有的RestTemplate以外,Spring 5中還引入了新的反應式WebClient。

支持響應式編程的HTTP客戶端(例如Reactor,Netty,Undertow)已經適應了一組響應式的ClientHttpRequest和ClientHttpResponse抽象,這些抽象將請求和響應主體公開爲Flux <DataBuffer>,而且在讀取和寫入端具備徹底的反壓支持。

Spring 5 Framework引入了Reactor做爲Reactive Streams規範的實現。

Reactor是下一代Reactive庫,用於在JVM上構建非阻塞應用程序。

Reactor擴展了基本的Reactive Streams Publisher合同,並定義了Flux和Mono API類型,以分別對0..N和0..1的數據序列提供聲明性操做。

Spring Web Reactive利用Servlet 3.1提供的非阻塞I / O並在Servlet 3.1容器上運行。

Spring WebFlux提供了兩種編程模型的選擇。

  1. 帶註釋的控制器:這些與Spring MVC相同,帶有一些Spring-Web模塊提供的附加註釋。Spring MVC和WebFlux控制器都支持Reactive返回類型。此外,WebFlux還支持Reactive @RequestBody參數。
  2. 函數式編程模型:一個基於lambda的輕量級小型庫,它公開實用程序來路由和處理請求。

 

Spring Web響應式與Spring Web MVC

Spring 5彼此相鄰容納了Spring Web Reactive(在spring-web-reactive模塊下)和Spring Web MVC(在spring-webmvc模塊下)。

儘管Spring Web Reactive和Spring Web MVC模塊都共享許多算法,可是因爲Spring Web Reactive可以在Reactive和非阻塞的Reactive Streams HTTP適配器層上運行,所以它們不共享代碼。

Spring MVC執行須要Servlet容器,而Spring Web Reactive也能夠在非Servlet運行時上運行,例如Netty和Undertow。

若是絕對須要帶有Java 8 lambda或Kotlin的輕量級功能性Web框架的無阻塞Web堆棧,則應考慮從Spring MVC應用程序切換到Spring Web Reactive。

響應式編程的基本配置

這是帶有5.0.0 M5版本和WebFlux依賴項的pom.xml。

 1 <parent>
 2     <groupId>org.springframework.boot</groupId>
 3     <artifactId>spring-boot-starter-parent</artifactId>
 4     <version>2.0.0.M5</version>
 5 </parent>
 6 <dependencies>         
 7     <dependency>
 8         <groupId>org.springframework.boot</groupId>
 9         <artifactId>spring-boot-starter-webflux</artifactId>                               </dependency>
10 </dependencies>

 

傳統方法與反應方法

在傳統方法中,執行將被阻止,並將一直等到服務執行完成。在下面的代碼中,在第一個打印語句以後,程序執行將被阻塞並等待服務執行完成。服務執行完成後,將恢復程序執行並執行第二個打印語句。

1 @GetMapping("/traditional")
2 public List < Product > getAllProducts() {
3     System.out.println("Traditional way started");
4     List < Product > products = prodService.getProducts("traditional");
5     System.out.println("Traditional way completed");
6     return products;
7 }

      

在響應式方法中,程序將繼續執行,而無需等待服務執行的完成。 在下面的代碼中,在第一個打印語句以後,第二個打印語句將以非阻塞方式執行,而無需等待服務執行完成。將使用產品數據填充Flux流。

1 @GetMapping(value = "/reactive", .TEXT_EVENT_STREAM_VALUE)
2 public Flux < Product > getAll() {
3     System.out.println("Reactive way using Flux started");
4     Flux < Product > fluxProducts = prodService.getProductsStream("Flux");
5     System.out.println("Reactive way using Flux completed");
6     return fluxProducts;
7 }

 

響應式Web客戶端

除了現有的RestTemplate以外,Spring 5還引入了Reactive WebClient。

ClientHttpRequest和ClientHttpResponse抽象將請求和響應主體公開爲Flux <DataBuffer>,在讀取和寫入側具備徹底的反壓支持。

來自Spring Core的Encoder和Decoder抽象也用於客戶端,用於與類型對象之間的字節通量序列化。

如下是一個Reactive WebClient的示例,該示例調用終結點並接收和處理Reactive Stream Flux對象。

1 @GetMapping("/accounts/{id}/alerts")
2 public Flux < Alert > getAccountAlerts(@PathVariable Long id) {
3     WebClient webClient = new WebClient(new ReactorClientHttpConnector());
4     return this.repository.getAccount(id).flatMap(account -> webClient.perform(get("/alerts/{key}", account.getKey())).extract(bodyStream(Alert.class)));
5 }

 

Spring 5的侷限性

  • 對響應式應用程序進行故障排除有些困難,而且有可能在解決問題時偶然引入了阻止代碼。
  • 大多數傳統的基於Java的集成庫仍處於阻塞狀態。
  • 除少數NoSQL數據庫(例如MongoDB)外,Reactive數據存儲區提供有限的選項。
  • 仍然不支持Spring Security。

感謝閱讀!

另外近期整理了一套完整的java架構思惟導圖,分享給一樣正在認真學習的每位朋友~

相關文章
相關標籤/搜索