淺談Spring 5 的響應式編程

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

響應式編程管理數據生產者與需要以非阻塞方式對數據做出反應的使用者之間的異步數據流。因此,響應式編程全部與異步和事件驅動的非阻塞應用程序有關,這些應用程序需要少量線程來擴展。

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

在響應式編程上下文中,“一切都是流,並且當流中有數據時,一切都以非阻塞的方式進行。”這篇分享至優銳課學習筆記的文章和大家淺談一下Spring 5 的響應式編程。


爲什麼響應式編程

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

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

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

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


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

·         大量交易處理服務,例如銀行業。

·         大型在線購物應用程序(例如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合約,例如HandlerMappingHandlerAdapter,以使它們異步和非阻塞並啓用 反應性HTTP請求和響應(以RouterFunctionHandlerFunction的形式)。

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

支持響應式編程的HTTP客戶端(例如ReactorNettyUndertow)已經適應了一組響應式的ClientHttpRequestClientHttpResponse抽象,這些抽象將請求和響應主體公開爲Flux <DataBuffer>,並且在讀取和寫入端具有完全的反壓支持。

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

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

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

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

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

1.     帶註釋的控制器:這些與Spring MVC相同,帶有一些Spring-Web模塊提供的附加註釋。Spring MVCWebFlux控制器都支持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 ReactiveSpring Web MVC模塊都共享許多算法,但是由於Spring Web Reactive能夠在Reactive和非阻塞的Reactive Streams HTTP適配器層上運行,因此它們不共享代碼。

Spring MVC執行需要Servlet容器,而Spring Web Reactive也可以在非Servlet運行時上運行,例如NettyUndertow

如果絕對需要帶有Java 8 lambdaKotlin的輕量級功能性Web框架的無阻塞Web堆棧,則應考慮從Spring MVC應用程序切換到Spring Web Reactive


響應式編程的基本配置

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

<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>2.0.0.M5</version>
</parent>
<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-webflux</artifactId>                               </dependency>
</dependencies>


 

傳統方法與反應方法

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

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


      

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

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


 

響應式Web客戶端

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

ClientHttpRequestClientHttpResponse抽象將請求和響應主體公開爲Flux <DataBuffer>,在讀取和寫入側具有完全的反壓支持。

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

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

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


 

Spring 5的侷限性

·         對響應式應用程序進行故障排除有些困難,並且有可能在解決問題時偶然引入了阻止代碼。

·         大多數傳統的基於Java的集成庫仍處於阻塞狀態。

·         除少數NoSQL數據庫(例如MongoDB)外,Reactive數據存儲區提供有限的選項。

·         仍然不支持Spring Security


感謝你的閱讀,希望能讓你有所收穫~

 


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章