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

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 前端技术 > javascript >内容正文

javascript

Spring Reactor教程

發(fā)布時(shí)間:2023/12/3 javascript 29 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Spring Reactor教程 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

在RESTful服務(wù)的世界中,實(shí)際上實(shí)際上是在幕后進(jìn)行許多工作,我們通常必須在應(yīng)用程序中進(jìn)行很多處理,而實(shí)際上并不會(huì)影響需要發(fā)送給真實(shí)用戶的響應(yīng)。 可以被動(dòng)地做出這些業(yè)務(wù)決策,以便它們對與應(yīng)用程序交互的用戶沒有任何影響。 Spring Framework為我們提供了一個(gè)出色的項(xiàng)目,稱為Spring Reactor項(xiàng)目,它使我們能夠在后臺(tái)很好地管理此后臺(tái)處理。 在學(xué)習(xí)本課程之前,我們必須注意一件事,即反應(yīng)式編程與并發(fā)編程并不相同 。

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

目錄

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

1.簡介

在本Spring Reactor課程中,我們將學(xué)習(xí)如何在Spring Boot項(xiàng)目中開始反應(yīng)性行為,以及如何在同一應(yīng)用程序本身中開始產(chǎn)生和使用消息。 除了一個(gè)簡單的項(xiàng)目外,當(dāng)有多個(gè)不同類型的請求處理程序時(shí),我們還將看到Spring Reactive流如何工作以及如何管理請求。

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

請注意,僅當(dāng)用戶不希望直接從應(yīng)用程序獲得響應(yīng)時(shí),才使用此應(yīng)用程序中演示的Reactor模式,因?yàn)槲覀儍H使用此Reactor演示執(zhí)行后臺(tái)作業(yè)。 當(dāng)開發(fā)人員可以為應(yīng)用程序分配更多的堆內(nèi)存(取決于該應(yīng)用程序?qū)⑹褂玫木€程數(shù))并且他們想并行執(zhí)行任務(wù)并且任務(wù)的執(zhí)行順序不合理時(shí),使用Reactor是一個(gè)很好的選擇。沒關(guān)系。 這一點(diǎn)實(shí)際上很重要,因此我們將通過重新措辭再說一遍,當(dāng)并行執(zhí)行作業(yè)時(shí),無法確認(rèn)作業(yè)的執(zhí)行順序

2. JVM中的Reactor

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

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

3.使用Maven制作Spring Boot項(xiàng)目

我們將使用許多Maven原型之一為我們的示例創(chuàng)建一個(gè)示例項(xiàng)目。 要?jiǎng)?chuàng)建項(xiàng)目,請?jiān)趯⒂米鞴ぷ骺臻g的目錄中執(zhí)行以下命令:

創(chuàng)建一個(gè)項(xiàng)目

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

如果您是第一次運(yùn)行maven,則完成生成命令將花費(fèi)幾秒鐘,因?yàn)閙aven必須下載所有必需的插件和工件才能完成生成任務(wù)。 運(yùn)行該項(xiàng)目后,我們將看到以下輸出并創(chuàng)建該項(xiàng)目:

Spring Reactor項(xiàng)目設(shè)置

4.添加Maven依賴項(xiàng)

創(chuàng)建項(xiàng)目后,請隨時(shí)在您喜歡的IDE中打開它。 下一步是向項(xiàng)目添加適當(dāng)?shù)腗aven依賴關(guān)系。 我們將在項(xiàng)目中使用以下依賴項(xiàng):

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

這是pom.xml文件,其中添加了適當(dāng)?shù)囊蕾図?xiàng):

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依賴項(xiàng)。 我們還為Spring引導(dǎo)項(xiàng)目添加了一個(gè)Maven插件,該插件可以幫助我們將該項(xiàng)目變成可運(yùn)行的JAR,以便無需任何現(xiàn)代工具和依賴項(xiàng)即可輕松部署該項(xiàng)目。 我們從此插件獲得的JAR已完全準(zhǔn)備好作為可執(zhí)行文件進(jìn)行部署。

最后,要了解添加此依賴項(xiàng)時(shí)添加到項(xiàng)目中的所有JAR,我們可以運(yùn)行一個(gè)簡單的Maven命令,當(dāng)我們向其添加一些依賴項(xiàng)時(shí),該命令使我們能夠查看項(xiàng)目的完整依賴關(guān)系樹。 當(dāng)我們以適當(dāng)?shù)膶哟谓Y(jié)構(gòu)方式添加一些自己的依賴項(xiàng)時(shí),此依賴關(guān)系樹還將顯示添加了多少個(gè)依賴項(xiàng)。 這是我們可以使用的相同命令:

檢查依賴樹

mvn dependency:tree

當(dāng)我們運(yùn)行此命令時(shí),它將向我們顯示以下依賴關(guān)系樹:

Maven依賴樹

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

5.項(xiàng)目結(jié)構(gòu)

在繼續(xù)進(jìn)行并開始為該項(xiàng)目編寫代碼之前,讓我們介紹一下一旦完成將所有代碼添加到項(xiàng)目中之后將擁有的項(xiàng)目結(jié)構(gòu),以便我們知道將在該項(xiàng)目中放置類的位置:

Spring Reactor項(xiàng)目結(jié)構(gòu)

我們將項(xiàng)目分為多個(gè)包,以便遵循關(guān)注點(diǎn)分離的原則,并且代碼保持模塊化,這使得項(xiàng)目的擴(kuò)展相當(dāng)容易。

6.了解示例應(yīng)用程序

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

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

  • 在數(shù)據(jù)庫中更新裝運(yùn)位置
  • 向用戶的移動(dòng)設(shè)備發(fā)送通知
  • 發(fā)送電子郵件通知
  • 發(fā)送短信給用戶

我們選擇對這些操作表現(xiàn)出反應(yīng)性行為,因?yàn)橛脩舨灰蕾囉谶@些操作是否實(shí)時(shí)準(zhǔn)確地進(jìn)行,因?yàn)樗鼈冎饕呛笈_(tái)任務(wù),這也可能會(huì)花費(fèi)一些時(shí)間,并且如果裝運(yùn)狀態(tài)更新晚了幾分鐘。 讓我們首先開始創(chuàng)建模型。

7.定義POJO模型

我們將從定義我們的POJO開始,該P(yáng)OJO表示要發(fā)送給客戶的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 }

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

8.定義服務(wù)

我們將定義一個(gè)基本接口,該接口定義我們接下來將要使用的功能的合同,該接口將定義一旦應(yīng)用程序消耗了偶數(shù)就需要執(zhí)行的業(yè)務(wù)邏輯。

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

ShipmentService.java

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

在此接口中,我們只有一個(gè)方法定義,因?yàn)檫@是我們現(xiàn)在所需要的。 現(xiàn)在讓我們繼續(xù)實(shí)現(xiàn)此服務(wù),在這里我們將實(shí)際演示一個(gè)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());} }

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

9.定義事件使用者

在本節(jié)中,我們最終將看到如何定義一個(gè)偵聽事件發(fā)運(yùn)位置更新的使用者。 可以通過將事件進(jìn)行裝運(yùn)更新來調(diào)用此使用者,該事件將在我們即將定義和使用的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}} }

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

此消費(fèi)者類的好處是,它從事件總線接收到了Shipment對象本身,并且無需在類本身中進(jìn)行轉(zhuǎn)換或強(qiáng)制轉(zhuǎn)換,這是常見的錯(cuò)誤區(qū)域,并且還增加了業(yè)務(wù)邏輯所需的時(shí)間執(zhí)行。

10.定義Java配置

我們可以在應(yīng)用程序中使用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);} }

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

11.定義Spring Boot類

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

應(yīng)用程序

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接口來使此類運(yùn)行代碼,從而可以測試所編寫的生產(chǎn)者和配置類代碼。 在此類中,我們將消息發(fā)布到指定的主題,并在我們在同一應(yīng)用程序中定義的使用者類中偵聽該消息。 請注意,我們使用Spring自己的事件總線來承載作業(yè),并且這些作業(yè)不會(huì)放在磁盤上。 如果使用Spring Boot執(zhí)行器正常終止了該應(yīng)用程序,則這些作業(yè)將自動(dòng)保留在磁盤上,以便在應(yīng)用程序重新啟動(dòng)時(shí)可以重新排隊(duì)。

在下一節(jié)中,我們將使用簡單的Maven命令運(yùn)行項(xiàng)目。

12.運(yùn)行項(xiàng)目

既然完成了主類定義,我們就可以運(yùn)行我們的項(xiàng)目。 使用maven可以輕松運(yùn)行應(yīng)用程序,只需使用以下命令:

pom.xml

mvn spring-boot:run

一旦執(zhí)行了以上命令,我們將看到一條消息已經(jīng)發(fā)布,并且同一應(yīng)用在事件處理程序中使用了該消息:

運(yùn)行Spring Reactor應(yīng)用程序

我們看到使用非阻塞模式下使用的CommandLineRunner方法啟動(dòng)應(yīng)用程序時(shí),事件已發(fā)布。 事件發(fā)布后,事件處理程序?qū)⒉⑿惺褂盟?如果仔細(xì)研究使用者,您會(huì)注意到Spring在線程池中定義了四個(gè)線程來管理這些事件。 這是Spring定義的用于并行管理事件的線程數(shù)的默認(rèn)限制。

13.結(jié)論

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

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

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

14.下載源代碼

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

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

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

總結(jié)

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

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。