這篇使用Spring 5進行響應式編程的入門文章展示了你現在可以使用的一些新的non-blocking, asynchronous。感謝優銳課老師給予的指導! 近年來,由於響應式編程能夠以聲明性的方式(而不是強制性的)構建應用程式,從而在響應程式和彈性方面具有更強的響應能力,因此在開發人員社區和客戶 ...
這篇使用Spring 5進行響應式編程的入門文章展示了你現在可以使用的一些新的non-blocking, asynchronous。感謝優銳課老師給予的指導!
近年來,由於響應式編程能夠以聲明性的方式(而不是強制性的)構建應用程式,從而在響應程式和彈性方面具有更強的響應能力,因此在開發人員社區和客戶中日益流行。Spring 5將Reactive Systems納入其核心框架的事實表明,範式已向聲明式編程轉移。
響應式編程管理數據生產者與需要以非阻塞方式對數據做出反應的使用者之間的非同步數據流。因此,響應式編程全部與非同步和事件驅動的非阻塞應用程式有關,這些應用程式需要少量線程來擴展。
由於基於共用的可變狀態,線程和鎖擴展應用程式存在很高的複雜性,因此很難使用基於線程的框架來構建反應性應用程式。
在響應式編程上下文中,“一切都是流,並且當流中有數據時,一切都以非阻塞的方式進行。”
為什麼響應式編程
響應式編程的高度抽象性提高了代碼的可讀性,因此開發人員可以主要關註定義業務邏輯的事件的相互依賴性。
反應模式自然適合高度併發環境中的消息處理,這是企業常見的用例。
具有強制背壓的功能,響應式方法最適合控制生產者和消費者之間的流量,這將有助於避免記憶體不足的問題。
響應式編程可以更有效地管理高度互動和實時的應用程式或任何動作/事件可能觸發多個連接子系統的通知的情況。
實現響應式編程的理想用例
- 大量交易處理服務,例如銀行業。
- 大型線上購物應用程式(例如Amazon)的通知服務。
- 股票交易同時變化的股票交易業務。
響應式流
“響應流”定義了一個API規範,該規範包含一組最少的介面,這些介面公開了用於定義具有非阻塞背壓的非同步數據流的操作和實體的方法。
引入反壓後,反應流允許訂戶控制發佈者的數據交換速率。
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提供了兩種編程模型的選擇。
- 帶註釋的控制器:這些與Spring MVC相同,帶有一些Spring-Web模塊提供的附加註釋。Spring MVC和WebFlux控制器都支持Reactive返回類型。此外,WebFlux還支持Reactive @RequestBody參數。
- 函數式編程模型:一個基於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架構思維導圖,分享給同樣正在認真學習的每位朋友~