日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 前端技术 > javascript >内容正文

javascript

Spring Reactor教程

發布時間:2023/12/3 javascript 30 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Spring Reactor教程 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

在RESTful服務的世界中,實際上實際上是在幕后進行許多工作,我們通常必須在應用程序中進行很多處理,而實際上并不會影響需要發送給真實用戶的響應。 可以被動地做出這些業務決策,以便它們對與應用程序交互的用戶沒有任何影響。 Spring Framework為我們提供了一個出色的項目,稱為Spring Reactor項目,它使我們能夠在后臺很好地管理此后臺處理。 在學習本課程之前,我們必須注意一件事,即反應式編程與并發編程并不相同

RESTful編程中用于響應行為的用例之一是,在大多數情況下,服務從根本上是阻塞和同步的。 響應式編程使我們可以擴展到同步線程的范圍之外,并且可以在不表現阻塞行為的情況下完成復雜的編排。 讓我們深入學習本課程,以了解如何將這種反應性行為集成到基于Spring Boot的應用程序中。

目錄

1.簡介 2. JVM中的Reactor 3.使用Maven制作Spring Boot項目 4.添加Maven依賴項 5.項目結構 6.了解示例應用程序 7.定義POJO模型 8.定義服務 9.定義事件使用者 10.定義Java配置 11.定義Spring Boot類 12.運行項目 13.結論 14.下載源代碼

1.簡介

在本Spring Reactor課程中,我們將學習如何在Spring Boot項目中開始反應性行為,以及如何在同一應用程序本身中開始產生和使用消息。 除了一個簡單的項目外,當有多個不同類型的請求處理程序時,我們還將看到Spring Reactive流如何工作以及如何管理請求。

隨著的起義微服務 ,涉及的服務之間的異步通信的必要性成為主流需求。 為了在涉及的各種服務之間進行通信,我們可以使用Apache Kafka之類的項目。 現在,異步通信對于同一應用程序中的耗時請求也很理想。 這是Spring Reactor的實際用例發揮作用的地方。

請注意,僅當用戶不希望直接從應用程序獲得響應時,才使用此應用程序中演示的Reactor模式,因為我們僅使用此Reactor演示執行后臺作業。 當開發人員可以為應用程序分配更多的堆內存(取決于該應用程序將使用的線程數)并且他們想并行執行任務并且任務的執行順序不合理時,使用Reactor是一個很好的選擇。沒關系。 這一點實際上很重要,因此我們將通過重新措辭再說一遍,當并行執行作業,無法確認作業的執行順序

2. JVM中的Reactor

正如Spring本身所言,Reactor是JVM上異步應用程序的基礎框架,它在適度的硬件上,可以用最快的非阻塞Dispatcher 每秒處理超過15,000,000個事件 。 聽起來,Reactor框架基于Reactor設計模式 。

關于Spring Reactor,最重要的是該框架為使用Spring開發應用程序的Java開發人員提供的抽象級別。 這種抽象使得在我們自己的應用程序中實現功能非常容易。 讓我們從一個示例項目開始,看看如何在接近現實的應用程序中使用該框架。 該反應堆項目還支持與反應堆IPC組件進行無阻塞的進程間通信(IPC),但其討論不在本課程的討論范圍之內。

3.使用Maven制作Spring Boot項目

我們將使用許多Maven原型之一為我們的示例創建一個示例項目。 要創建項目,請在將用作工作空間的目錄中執行以下命令:

創建一個項目

mvn archetype:generate -DgroupId=com.javacodegeeks.example -DartifactId=JCG-BootReactor-Example -DarchetypeArtifactId=maven-archetype-quickstart -DinteractiveMode=false

如果您是第一次運行maven,則完成生成命令將花費幾秒鐘,因為maven必須下載所有必需的插件和工件才能完成生成任務。 運行該項目后,我們將看到以下輸出并創建該項目:

Spring Reactor項目設置

4.添加Maven依賴項

創建項目后,請隨時在您喜歡的IDE中打開它。 下一步是向項目添加適當的Maven依賴關系。 我們將在項目中使用以下依賴項:

  • spring-boot-starter-web :此依賴關系將該項目標記為Web項目,并添加了依賴關系以創建控制器并創建與Web相關的類
  • reactor-bus :這是將所有與Reactor相關的依賴項引入項目類路徑的依賴項
  • spring-boot-starter-test :此依賴項將所有與測試相關的JAR收集到項目中,例如JUnit和Mockito

這是pom.xml文件,其中添加了適當的依賴項:

pom.xml

<parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>1.5.10.RELEASE</version><relativePath/> <!-- lookup parent from repository --></parent><properties><project.build.sourceEncoding>UTF-8</project.build.sourceEncoding><project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding><java.version>1.8</java.version></properties><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>io.projectreactor</groupId><artifactId>reactor-bus</artifactId><version>2.0.8.RELEASE</version></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency></dependencies><build><plugins><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId></plugin></plugins></build>

在Maven Central上找到最新的Maven依賴項。 我們還為Spring引導項目添加了一個Maven插件,該插件可以幫助我們將該項目變成可運行的JAR,以便無需任何現代工具和依賴項即可輕松部署該項目。 我們從此插件獲得的JAR已完全準備好作為可執行文件進行部署。

最后,要了解添加此依賴項時添加到項目中的所有JAR,我們可以運行一個簡單的Maven命令,當我們向其添加一些依賴項時,該命令使我們能夠查看項目的完整依賴關系樹。 當我們以適當的層次結構方式添加一些自己的依賴項時,此依賴關系樹還將顯示添加了多少個依賴項。 這是我們可以使用的相同命令:

檢查依賴樹

mvn dependency:tree

當我們運行此命令時,它將向我們顯示以下依賴關系樹:

Maven依賴樹

注意到了什么? 只需在項目中添加三個依賴項,即可添加如此多的依賴項。 Spring Boot本身會收集所有相關的依賴項,因此在此方面不做任何事情。 最大的優點是,由于Spring Boot項目的pom文件本身可以管理和提供這些依賴關系,因此可以確保所有這些依賴關系相互兼容。

5.項目結構

在繼續進行并開始為該項目編寫代碼之前,讓我們介紹一下一旦完成將所有代碼添加到項目中之后將擁有的項目結構,以便我們知道將在該項目中放置類的位置:

Spring Reactor項目結構

我們將項目分為多個包,以便遵循關注點分離的原則,并且代碼保持模塊化,這使得項目的擴展相當容易。

6.了解示例應用程序

為了使應用程序易于理解并且接近實際情況,我們將考慮一種物流應用程序的場景,該應用程序管理放置在系統中的各種貨物的交付。

該應用程序從外部供應商處接收有關在給定地址處交付給客戶的貨件位置的更新。 我們的應用程序收到此更新后,便會執行各種操作,例如:

  • 在數據庫中更新裝運位置
  • 向用戶的移動設備發送通知
  • 發送電子郵件通知
  • 發送短信給用戶

我們選擇對這些操作表現出反應性行為,因為用戶不依賴于這些操作是否實時準確地進行,因為它們主要是后臺任務,這也可能會花費一些時間,并且如果裝運狀態更新晚了幾分鐘。 讓我們首先開始創建模型。

7.定義POJO模型

我們將從定義我們的POJO開始,該POJO表示要發送給客戶的shipmentId ,該shipmentId具有currentLocation , currentLocation等字段。讓我們在這里定義此POJO:

Shipment.java

package com.javacodegeeks.example.model;public class Shipment {private String shipmentId;private String name;private String currentLocation;private String deliveryAddress;private String status;//standard setters and getters }

我們在這里定義了一些基本字段。 為了簡潔起見,我們省略了標準的getter和setter方法,但是由于Jackson在對象的序列化和反序列化過程中使用它們,因此必須將它們制成。

8.定義服務

我們將定義一個基本接口,該接口定義我們接下來將要使用的功能的合同,該接口將定義一旦應用程序消耗了偶數就需要執行的業務邏輯。

這是我們將使用的合同定義:

ShipmentService.java

package com.javacodegeeks.example.service;import com.javacodegeeks.example.model.Shipment;public interface ShipmentService {void shipmentLocationUpdate(Shipment shipment); }

在此接口中,我們只有一個方法定義,因為這是我們現在所需要的。 現在讓我們繼續實現此服務,在這里我們將實際演示一個sleep方法,該方法只是模擬此類的操作行為:

ShipmentServiceImpl.java

package com.javacodegeeks.example.service;import com.javacodegeeks.example.model.Shipment; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.stereotype.Service;@Service public class ShipmentServiceImpl implements ShipmentService {private final Logger LOG = LoggerFactory.getLogger("ShipmentService");@Overridepublic void shipmentLocationUpdate(Shipment shipment) throws InterruptedException {LOG.info("Shipment data: {}", shipment.getShipmentId());Thread.sleep(3000);LOG.info("Shipment with ID: {} reached at javacodegeeks!!!", shipment.getShipmentId());} }

出于說明目的,在調用此服務并附帶裝運詳細信息時,它僅提供一些打印語句,使用3000毫秒的延遲來實現我們在上一節中定義的操作可能要花費的時間。 請注意,這些操作中的每一個可能花費的時間遠遠超過3秒,但是應用程序沒有時間(直到線程開始堆積在需要管理的應用程序的堆內存上)。

9.定義事件使用者

在本節中,我們最終將看到如何定義一個偵聽事件發運位置更新的使用者。 可以通過將事件進行裝運更新來調用此使用者,該事件將在我們即將定義和使用的SPring的EventBus上放置。

EventHandler.java

package com.javacodegeeks.example.handler;import com.javacodegeeks.example.model.Shipment; import com.javacodegeeks.example.service.ShipmentService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import reactor.bus.Event; import reactor.fn.Consumer;@Service public class EventHandler implements Consumer<Event<Shipment>> {private final ShipmentService shipmentService;@Autowiredpublic EventHandler(ShipmentService shipmentService) {this.shipmentService = shipmentService;}@Overridepublic void accept(Event<Shipment> shipmentEvent) {Shipment shipment = shipmentEvent.getData();try {shipmentService.shipmentLocationUpdate(shipment);} catch (InterruptedException e) {//do something as bad things have happened}} }

此使用者服務在事件總線中接受該對象,并通知我們的服務類,以便它可以異步執行必要的操作。 請注意,我們還將定義一個線程池,該線程池將用于運行此使用者,以便可以使用不同的線程來運行服務方法調用。 即使我們自己沒有定義線程池,Spring Boot也會使用固定數量的最大線程池為我們完成此任務。

此消費者類的好處是,它從事件總線接收到了Shipment對象本身,并且無需在類本身中進行轉換或強制轉換,這是常見的錯誤區域,并且還增加了業務邏輯所需的時間執行。

10.定義Java配置

我們可以在應用程序中使用Java定義配置。 讓我們在這里做這些定義:

ReactorConfig.java

package com.javacodegeeks.example.config;import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import reactor.Environment; import reactor.bus.EventBus;@Configuration public class ReactorConfig {@BeanEnvironment env() {return Environment.initializeIfEmpty().assignErrorJournal();}@BeanEventBus createEventBus(Environment env) {return EventBus.create(env, Environment.THREAD_POOL);} }

顯然,這里沒有什么特別的。 我們只是用一些數字(這里是默認值)初始化了線程池。 我們只是想演示如何根據您的應用程序用例來更改線程數。

11.定義Spring Boot類

在最后階段,我們將創建Spring Boot類,通過該類我們可以發布一條消息,該消息可以由我們先前定義的事件處理程序使用。 這是主類的類定義:

應用程序

package com.javacodegeeks.example;import com.javacodegeeks.example.handler.EventHandler; import com.javacodegeeks.example.model.Shipment; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.CommandLineRunner; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import reactor.bus.Event; import reactor.bus.EventBus;import static reactor.bus.selector.Selectors.$;@SpringBootApplication public class Application implements CommandLineRunner {private final Logger LOG = LoggerFactory.getLogger("Application");private final EventBus eventBus;private final EventHandler eventHandler;@Autowiredpublic Application(EventBus eventBus, EventHandler eventHandler) {this.eventBus = eventBus;this.eventHandler = eventHandler;}public static void main(String[] args) {SpringApplication.run(Application.class, args);}@Overridepublic void run(String... strings) throws Exception {eventBus.on($("eventHandler"), eventHandler);//Publish messages herefor (int i = 0; i < 10; i++) {Shipment shipment = new Shipment();shipment.setShipmentId(String.valueOf(i));eventBus.notify("eventHandler", Event.wrap(shipment));LOG.info("Published shipment number {}.", i);}} }

我們使用了CommandLineRunner接口來使此類運行代碼,從而可以測試所編寫的生產者和配置類代碼。 在此類中,我們將消息發布到指定的主題,并在我們在同一應用程序中定義的使用者類中偵聽該消息。 請注意,我們使用Spring自己的事件總線來承載作業,并且這些作業不會放在磁盤上。 如果使用Spring Boot執行器正常終止了該應用程序,則這些作業將自動保留在磁盤上,以便在應用程序重新啟動時可以重新排隊。

在下一節中,我們將使用簡單的Maven命令運行項目。

12.運行項目

既然完成了主類定義,我們就可以運行我們的項目。 使用maven可以輕松運行應用程序,只需使用以下命令:

pom.xml

mvn spring-boot:run

一旦執行了以上命令,我們將看到一條消息已經發布,并且同一應用在事件處理程序中使用了該消息:

運行Spring Reactor應用程序

我們看到使用非阻塞模式下使用的CommandLineRunner方法啟動應用程序時,事件已發布。 事件發布后,事件處理程序將并行使用它。 如果仔細研究使用者,您會注意到Spring在線程池中定義了四個線程來管理這些事件。 這是Spring定義的用于并行管理事件的線程數的默認限制。

13.結論

在本課程中,我們研究了構建集成了Reactor項目的Spring Boot應用是多么容易和快捷。 就像我們已經說過的那樣,在您的應用程序中設計良好的反應堆模式可以具有每秒高達15,000,000(即六個零 )事件的吞吐量。 這表明該反應堆內部隊列的執行效率如何。

在我們定義的小型應用程序中,我們演示了一種定義線程池執行程序的簡單方法,該執行程序定義了四個線程,而使用者使用該線程池來并行管理事件。 在依賴異步行為執行操作的應用程序中面臨的最常見問題之一是,當有多個線程開始占用堆空間并在開始處理時創建對象時,它們很快就會耗盡內存。 確保啟動應用程序時,我們為應用程序分配良好的堆大小非常重要,這直接取決于為應用程序定義的線程池的大小。

反應式編程是最常見的編程風格之一,由于應用程序開始通過并行執行來利用CPU內核,因此這是一種正在興起的編程風格,這是在應用程序級別使用硬件的好主意。 Reactor為JVM提供了完整的非阻塞編程基礎,并且也可用于Groovy或Kotlin。 由于Java本身不是反應性語言,因此它本身不支持協程。 有多種JVM語言(例如Scala和Clojure)就本機性而言更好地支持反應模型,但是Java本身并沒有做到這一點(至少直到版本9才如此)。

14.下載源代碼

這是帶有Spring Boot和Reactor模式的Java編程語言的示例。

下載
您可以在此處下載此示例的完整源代碼: Reactor示例

翻譯自: https://www.javacodegeeks.com/2018/06/spring-reactor-tutorial.html

總結

以上是生活随笔為你收集整理的Spring Reactor教程的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。