Uvod u projektnu sabirnicu reaktora

1. Pregled

U ovom ćemo kratkom članku predstaviti sabirnicu reaktora postavljanjem scenarija iz stvarnog života za reaktivnu aplikaciju vođenu događajima.

2. Osnove projektnog reaktora

2.1. Zašto Reactor?

Moderne aplikacije moraju se nositi s ogromnim brojem istodobnih zahtjeva i obraditi značajnu količinu podataka. Standardni kod za blokiranje više nije dovoljan za ispunjavanje ovih zahtjeva.

Uzorak reaktivnog dizajna je arhitektonski pristup zasnovan na događajima za asinkrono rukovanje velikim brojem istodobnih zahtjeva za uslugom koji dolaze od jednog ili više rukovatelja uslugama.

Projektni reaktor temelji se na ovom obrascu i ima jasan i ambiciozan cilj izgraditi neblokirajuće, reaktivne aplikacije na JVM-u.

2.2. Primjeri scenarija

Prije nego što započnemo, evo nekoliko zanimljivih scenarija gdje bi korištenje reaktivnog arhitektonskog stila imalo smisla, samo da bismo stekli ideju gdje bismo ga mogli primijeniti:

  • Usluge obavijesti za veliku platformu za online kupnju poput Amazona
  • Ogromne usluge obrade transakcija za bankarski sektor
  • Dionice koje trguju poduzećima gdje se cijene dionica istodobno mijenjaju

3. Ovisnosti Mavena

Počnimo koristiti Project Reactor Bus dodavanjem sljedeće ovisnosti u našu pom.xml:

 io.projectreactor reaktor-sabirnica 2.0.8.OBUSTAŽENJE 

Možemo provjeriti najnoviju verziju reaktor-sabirnica u Maven Central.

4. Izrada demo aplikacije

Da bismo bolje razumjeli blagodati pristupa zasnovanog na reaktorima, pogledajmo praktični primjer.

Izgradit ćemo jednostavnu aplikaciju odgovornu za slanje obavijesti korisnicima mrežne platforme za kupnju. Na primjer, ako korisnik postavi novu narudžbu, tada aplikacija šalje potvrdu narudžbe putem e-pošte ili SMS-a.

Tipična sinkrona implementacija prirodno bi bila ograničena protokom usluge e-pošte ili SMS-a. Stoga bi skokovi prometa, poput praznika, uglavnom bili problematični.

Reaktivnim pristupom možemo svoj sustav dizajnirati tako da bude fleksibilniji i da se bolje prilagodi kvarovima ili vremenskim ograničenjima koji se mogu pojaviti u vanjskim sustavima, poput gateway poslužitelja.

Pogledajmo primjenu - počevši od tradicionalnijih aspekata i prelazeći na reaktivnije konstrukcije.

4.1. Jednostavno POJO

Prvo, kreirajmo POJO klasu koja će predstavljati podatke obavijesti:

javna klasa NotificationData {private long id; privatni naziv niza; privatni String e-mail; privatni String mobitel; // metode dobivanja i postavljanja}

4.2. Razina usluge

Definirajmo sada jednostavan sloj usluge:

javno sučelje NotificationService {void initiateNotification (NotificationData notificationData) baca InterruptedException; }

I implementacija, koja simulira dugotrajnu operaciju:

@Service javna klasa NotificationServiceimpl implementira NotificationService {@Override public void InitiateNotification (NotificationData notificationData) baca InterruptedException {System.out.println ("Usluga obavijesti pokrenuta za" + "ID obavijesti:" + notificationData.getId ()); Navoj.spavanje (5000); System.out.println ("Usluga obavještavanja završena za" + "ID obavijesti:" + notificationData.getId ()); }}

Primijetite da za ilustraciju stvarnog scenarija slanja poruka putem SMS-a ili e-mail pristupnika, namjerno uvodimo pet sekundi odgode u iniciratiNotification metoda sa Navoj.spavanje (5000).

Slijedom toga, kada nit pogodi uslugu, bit će blokirana na pet sekundi.

4.3. Potrošač

Krenimo sada u reaktivnije aspekte naše aplikacije i implementiramo potrošača - kojeg ćemo zatim preslikati na sabirnicu reaktora:

@Service javna klasa NotificationConsumer implementira Consumer {@Autowired private NotificationService notificationService; @Override public void accept (Event notificationDataEvent) {NotificationData notificationData = notificationDataEvent.getData (); isprobajte {notificationService.initiateNotification (notificationData); } catch (InterruptedException e) {// zanemarivanje}}}

Kao što vidimo, potrošač kojeg smo stvorili implementira Potrošač sučelje. Glavna logika nalazi se u prihvatiti metoda.

Ovo je sličan pristup koji možemo susresti u tipičnoj provedbi slušatelja Springa.

4.4. Kontroler

Napokon, sada kad smo u mogućnosti konzumirati događaje, hajde da ih i generiramo.

To ćemo učiniti na jednostavnom kontroleru:

@Controller javna klasa NotificationController {@Autowired private EventBus eventBus; @GetMapping ("/ startNotification / {param}") javna void startNotification (@PathVariable Integer param) {for (int i = 0; i <param; i ++) {NotificationData data = new NotificationData (); data.setId (i); eventBus.notify ("notificationConsumer", Event.wrap (podaci)); System.out.println ("Obavijest" + i + ": zadatak obavijesti uspješno poslan"); }}}

Ovo je sasvim samorazumljivo - emitiramo događaje kroz EventBus ovdje.

Na primjer, ako klijent pogodi URL s param vrijednošću deset, tada će se deset događaja poslati kroz sabirnicu događaja.

4.5. Java Config

Sastavimo sada sve i stvorimo jednostavnu aplikaciju Spring Boot.

Prvo, moramo konfigurirati EventBus i Okoliš grah:

@Configuration javna klasa Config {@Bean public Environment env () {return Environment.initializeIfEmpty (). AssignErrorJournal (); } @Bean public EventBus createEventBus (Environment env) {return EventBus.create (env, Environment.THREAD_POOL); }}

U našem slučaju, instanciramo EventBus sa zadanim spremištem niti dostupnim u okolini.

Alternativno, možemo koristiti prilagođene Dispečer primjer:

EventBus evBus = EventBus.create (env, Environment.newDispatcher (REACTOR_CAPACITY, REACTOR_CONSUMERS_COUNT, DispatcherType.THREAD_POOL_EXECUTOR));

Sada smo spremni stvoriti glavni kod aplikacije:

uvoz statičkog reaktora.bus.selector.Selectors. $; @SpringBootApplication javna klasa NotificationApplication implementira CommandLineRunner {@Autowired private EventBus eventBus; @Autowired privatni NotificationConsumer notificationConsumer; @Override public void run (String ... args) baca iznimku {eventBus.on ($ ("notificationConsumer"), notificationConsumer); } javna statička void glavna (String [] args) {SpringApplication.run (NotificationApplication.class, args); }}

U našem trčanje metoda registriramo notificationConsumer da se aktivira kada se obavijest podudara s danim biračem.

Primijetite kako koristimo statički uvoz datoteke $ atribut za stvaranje a Selektor objekt.

5. Testirajte prijavu

Izradimo sada test da vidimo naše NotificationApplication u akciji:

@RunWith (SpringRunner.class) @SpringBootTest (webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) javna klasa NotificationApplicationIntegrationTest {@LocalServerPort private int port; @Test javna praznina givenAppStarted_whenNotificationTasksSubmitted_thenProcessed () {RestTemplate restTemplate = novi RestTemplate (); restTemplate.getForObject ("// localhost:" + port + "/ startNotification / 10", String.class); }}

Kao što vidimo, čim se izvrši zahtjev, svih deset zadaci se odmah predaju bez stvaranja blokade. A nakon što se prijave, događaji obavijesti obrađuju se paralelno.

Obavijest 0: zadatak obavijesti uspješno podnijet Obavijest 1: zadatak obavijesti uspješno podnijet Obavijest 2: zadatak obavijesti uspješno podnijet Obavijest 3: zadatak obavijesti uspješno podnijet Obavijest 4: zadatak obavijesti uspješno podnijet Obavijest 5: zadatak obavijesti uspješno podnijet Obavijest 6: zadatak obavijesti uspješno predan Obavijest 7: zadatak obavještavanja uspješno poslan Obavijest 8: zadatak obavještavanja uspješno podnijet Obavijest 9: zadatak obavještavanja uspješno podnijet Usluga obavijesti pokrenuta za Notification ID: 1 Usluga obavijesti pokrenuta za Notification ID: 2 Usluga obavijesti pokrenuta za Notification ID: 3 Usluga obavijesti pokrenuta za Notification ID : 0 Završena usluga obavijesti za ID obavijesti: 1 Završena usluga obavijesti za ID obavijesti: 0 Pokrenuta usluga obavijesti za ID obavijesti: 4 Usluga obavijesti završena za ID obavijesti: 3 Usluga obavijesti završilo za ID obavijesti: 2 Započela usluga obavijesti za ID obavijesti: 6 Pokrenula se usluga obavijesti za ID obavijesti: 5 Usluga obavijesti započela za ID obavijesti: 7 Usluga obavijesti završila za ID obavijesti: 4 Usluga obavijesti započela za ID obavijesti: 8 Usluga obavijesti završila za ID obavijesti: 6 Završena usluga obavijesti za ID obavijesti: 5 Usluga obavijesti započeta za ID obavijesti: 9 Usluga obavijesti završena za ID obavijesti: 7 Usluga obavijesti završena za ID obavijesti: 8 Usluga obavijesti završena za ID obavijesti: 9

Važno je imati na umu da u našem scenariju nema potrebe za obradom tih događaja u bilo kojem određenom redoslijedu.

6. Zaključak

U ovom brzom vodiču, stvorili smo jednostavnu aplikaciju vođenu događajima. Također smo vidjeli kako započeti pisanje reaktivnijeg i neblokirajućeg koda.

Međutim, ovaj scenarij samo ogrebe površinu subjekta i predstavlja samo dobru osnovu za početak eksperimentiranja s reaktivnom paradigmom.

Kao i uvijek, izvorni kod dostupan je na GitHub-u.


$config[zx-auto] not found$config[zx-overlay] not found