Programmering

Mastering Spring framework 5, Part 2: Spring WebFlux

Spring WebFlux introducerer reaktiv webudvikling til Spring-økosystemet. Denne artikel vil komme i gang med reaktive systemer og reaktiv programmering med Spring. Først finder du ud af, hvorfor reaktive systemer er vigtige, og hvordan de implementeres i Spring Framework 5, så får du en praktisk introduktion til opbygning af reaktive tjenester ved hjælp af Spring WebFlux. Vi bygger vores første reaktive applikation ved hjælp af annoteringer. Jeg vil også vise dig, hvordan du bygger en lignende applikation ved hjælp af Spring's nyere funktionelle funktioner.

Forårstudier om JavaWorld

Hvis du er ny i Spring-rammen, anbefaler jeg, at du starter med en af ​​de tidligere tutorials i denne serie:

  • Hvad er forår? Komponentbaseret udvikling til Java
  • Mastering Spring framework 5: Spring MVC

Reaktive systemer og Spring WebFlux

Begrebet reaktiv er i øjeblikket populær blandt udviklere og it-ledere, men jeg har bemærket en vis usikkerhed om, hvad det faktisk betyder. For at få klarere, hvad reaktive systemer er, er det nyttigt at forstå det grundlæggende problem, de er designet til at løse. I dette afsnit vil vi tale om reaktive systemer generelt, og jeg introducerer Reactive Streams API til Java-applikationer.

Skalerbarhed i foråret MVC

Spring MVC har optjent sin plads blandt de bedste valg til opbygning af Java-webapplikationer og webtjenester. Som vi opdagede i Mastering Spring framework 5, Part 1, integrerer Spring MVC problemfrit annoteringer i den robuste arkitektur i en Spring-baseret applikation. Dette gør det muligt for udviklere, der er fortrolige med Spring, hurtigt at opbygge tilfredsstillende, meget funktionelle webapplikationer. Skalerbarhed er dog en udfordring for Spring MVC-applikationer. Det er problemet, som Spring WebFlux søger at løse.

Blokering vs ikke-blokerende webrammer

I traditionelle webapplikationer, når en webserver modtager en anmodning fra en klient, accepterer den anmodningen og placerer den i en udførelseskø. En tråd i udførelseskøens trådpul modtager derefter anmodningen, læser dens inputparametre og genererer et svar. Undervejs, hvis udførelsestråden skal ringe til en blokerende ressource - såsom en database, et filsystem eller en anden webtjeneste - udfører tråden blokeringsanmodningen og afventer et svar. I dette paradigme blokeres tråden effektivt, indtil den eksterne ressource reagerer, hvilket forårsager ydelsesproblemer og begrænser skalerbarhed. For at bekæmpe disse problemer opretter udviklere generøst trådpuljer, så mens en tråd er blokeret, kan en anden tråd fortsætte med at behandle anmodninger. Figur 1 viser eksekveringsflowet for en traditionel, blokerende webapplikation.

Steven Haines

Ikke-blokerende webrammer som NodeJS og Play tager en anden tilgang. I stedet for at udføre en blokeringsanmodning og vente på, at den er færdig, bruger de ikke-blokerende I / O. I dette paradigme udfører en applikation en anmodning, giver kode, der skal udføres, når et svar returneres, og giver derefter tråden tilbage til serveren. Når en ekstern ressource returnerer et svar, udføres den angivne kode. Internt fungerer ikke-blokerende rammer ved hjælp af en begivenhedssløjfe. Inden for sløjfen giver applikationskoden enten et tilbagekald eller en fremtid, der indeholder koden, der skal udføres, når den asynkrone sløjfe er færdig.

Af natur er ikke-blokerende rammer det Hændelsesdrevet. Dette kræver et andet programmeringsparadigme og en ny tilgang til ræsonnement om, hvordan din kode vil blive udført. Når du har pakket hovedet omkring det, kan reaktiv programmering føre til meget skalerbare applikationer.

Tilbagekaldelser, løfter og futures

I de tidlige dage håndterede JavaScript al asynkron funktionalitet via tilbagekald. I dette scenarie udføres tilbagekaldelsen, når en begivenhed opstår (f.eks. Når et svar fra et servicekald bliver tilgængeligt). Mens tilbagekald stadig er udbredt, er JavaScript's asynkrone funktionalitet for nylig flyttet til løfter. Med løfter vender et funktionsopkald straks tilbage og returnerer et løfte om at levere resultaterne på et fremtidigt tidspunkt. I stedet for løfter implementerer Java et lignende paradigme ved hjælp af futures. I denne anvendelse returnerer en metode en fremtid, der vil have en værdi på et eller andet tidspunkt i fremtiden.

Reaktiv programmering

Du har måske hørt ordet reaktiv programmering relateret til webudviklingsrammer og -værktøjer, men hvad betyder det egentlig? Udtrykket, som vi er kommet til at kende, stammer fra det reaktive manifest, som definerer reaktive systemer som fire kernetræk:

  1. Reaktive systemer er lydhør, hvilket betyder at de reagerer rettidigt under alle mulige omstændigheder. De fokuserer på at levere hurtige og ensartede svartider, etablere pålidelige øvre grænser, så de leverer en ensartet servicekvalitet.
  2. Reaktive systemer er robust, hvilket betyder at de forbliver lydhøre over for fiasko. Modstandsdygtighed opnås ved teknikkerne til replikering, indeslutning, isolation og delegering. Ved at isolere applikationskomponenter fra hinanden kan du indeholde fejl og beskytte systemet som helhed.
  3. Reaktive systemer er elastisk, hvilket betyder, at de forbliver lydhøre under forskellige arbejdsbelastninger. Dette opnås ved at skalere applikationskomponenterne elastisk for at imødekomme det aktuelle behov.
  4. Reaktive systemer er meddelelsesdrevet, hvilket betyder at de stoler på asynkron meddelelse, der går mellem komponenter. Dette giver dig mulighed for at skabe løs kobling, isolering og placeringsgennemsigtighed.

Figur 2 viser, hvordan disse træk flyder sammen i et reaktivt system.

Steven Haines

Karakteristika ved et reaktivt system

Reaktive systemer er bygget ved at skabe isolerede komponenter, der kommunikerer med hinanden asynkront og kan skaleres hurtigt for at imødekomme den aktuelle belastning. Komponenter fejler stadig i reaktive systemer, men der er definerede handlinger, der skal udføres som et resultat af denne fejl, hvilket holder systemet som helhed funktionelt og lydhørt.

Det Reaktivt manifest er abstrakt, men reaktive anvendelser er typisk karakteriseret ved følgende komponenter eller teknikker:

  • Datastrømme: A strøm er en række hændelser, der er bestilt i tide, såsom brugerinteraktioner, REST-servicekald, JMS-meddelelser og resultater fra en database.
  • Asynkron: Datastrømshændelser fanges asynkront, og din kode definerer, hvad der skal gøres, når en begivenhed udsendes, når der opstår en fejl, og når strømmen af ​​begivenheder er afsluttet.
  • Ikke-blokering: Når du behandler begivenheder, skal din kode ikke blokere og udføre synkrone opkald; i stedet skal den foretage asynkrone opkald og svare, når resultaterne af disse opkald returneres.
  • Rygpres: Komponenter styrer antallet af begivenheder, og hvor ofte de udsendes. I reaktive termer kaldes din komponent for abonnent og begivenheder udsendes af en forlægger. Dette er vigtigt, fordi abonnenten har kontrol over, hvor meget data den modtager og således ikke overbelaster sig selv.
  • Fejlmeddelelser: I stedet for at komponenter kaster undtagelser, sendes fejl som meddelelser til en handlerfunktion. Mens undtagelser med at kaste bryder strømmen, definerer det ikke en funktion, der skal håndtere fejl, som de opstår.

API'en til reaktive streams

Den nye Reactive Streams API blev oprettet af ingeniører fra blandt andet Netflix, Pivotal, Lightbend, RedHat, Twitter og Oracle. Udgivet i 2015 er Reactive Streams API nu en del af Java 9. Den definerer fire grænseflader:

  • Forlægger: Afsender en række begivenheder til abonnenter.
  • Abonnent: Modtager og behandler begivenheder, der udsendes af en udgiver.
  • Abonnement: Definerer et en-til-en-forhold mellem en udgiver og en abonnent.
  • Processor: Representerer et behandlingsstadium bestående af både en abonnent og en udgiver og overholder begge kontrakter.

Figur 3 viser forholdet mellem en udgiver, abonnent og abonnement.

Steven Haines

I det væsentlige opretter en abonnent et abonnement på en udgiver, og når udgiveren har tilgængelige data, sender den en begivenhed til abonnenten med en strøm af elementer. Bemærk, at abonnenten administrerer sit modtryk inde i abonnementet på udgiveren.

Nu hvor du kender lidt til reaktive systemer og Reactive Streams API, skal vi rette opmærksomheden mod de værktøjer, som Spring bruger til at implementere reaktive systemer: Spring WebFlux og Reactor-biblioteket.

Projektreaktor

Project Reactor er en tredjepartsramme baseret på Java's Reactive Streams Specification, som bruges til at opbygge ikke-blokerende webapplikationer. Project Reactor tilbyder to udgivere, der er meget anvendte i Spring WebFlux:

  • Mono: Returnerer 0 eller 1 element.
  • Strøm: Returnerer 0 eller flere elementer. En Flux kan være uendelig, hvilket betyder, at den kan fortsætte med at udsende elementer for evigt, eller den kan returnere en sekvens af elementer og derefter sende en afslutningsmeddelelse, når den har returneret alle dens elementer.

Monoer og strømme ligner konceptuelt futures, men mere magtfulde. Når du påberåber en funktion, der returnerer en mono eller en flux, vender den straks tilbage. Resultaterne af funktionsopkaldet vil blive leveret til dig via mono eller flux, når de bliver tilgængelige.

I Spring WebFlux vil du kalde reaktive biblioteker, der returnerer monoer og strømme, og dine controllere vil returnere monoer og strømme. Fordi disse vender tilbage med det samme, vil dine controllere effektivt opgive deres tråde og give Reactor mulighed for at håndtere svar asynkront. Det er vigtigt at bemærke, at kun ved hjælp af reaktive biblioteker kan dine WebFlux-tjenester forblive reaktive. Hvis du bruger ikke-reaktive biblioteker, såsom JDBC-opkald, blokerer din kode og venter på, at disse opkald er afsluttet, før du vender tilbage.

Reaktiv programmering med MongoDB

I øjeblikket er der ikke mange reaktive databasebiblioteker, så du undrer dig måske over, om det er praktisk at skrive reaktive tjenester. Den gode nyhed er, at MongoDB har reaktiv support, og der er et par tredjeparts reaktive databasedrivere til MySQL og Postgres. For alle andre brugssager tilvejebringer WebFlux en mekanisme til at udføre JDBC-opkald på en reaktiv måde, omend ved hjælp af en sekundær trådpulje, der foretager blokering af JDBC-opkald.

Kom godt i gang med Spring WebFlux

I vores første eksempel gør vi en simpel bogtjeneste, der fortsætter bøger til og fra MongoDB på en reaktiv måde.

Start med at navigere til Spring Initializr-hjemmesiden, hvor du vælger en Maven projekt med Java og vælg den nyeste version af Spring Boot (2.0.3 på tidspunktet for denne skrivning). Giv dit projekt et gruppenavn, såsom "com.javaworld.webflux" og et artefaktnavn, såsom "bookservice". Udvid Skift til den fulde version link for at vise den fulde liste over afhængigheder. Vælg følgende afhængigheder for eksempelprogrammet:

  • Internet -> Reaktivt web: Denne afhængighed inkluderer Spring WebFlux.
  • NoSQL -> Reaktiv MongoDB: Denne afhængighed inkluderer de reaktive drivere til MongoDB.
  • NoSQL -> Indlejret MongoDB: Denne afhængighed giver os mulighed for at køre en integreret version af MongoDB, så der er ikke behov for at installere en separat forekomst. Normalt bruges dette til test, men vi inkluderer det i vores udgivelseskode for at undgå installation af MongoDB.
  • Kerne -> Lombok: Brug af Lombok er valgfrit, da du ikke har brug for det til at oprette et Spring WebFlux-program. Fordelen ved at bruge Project Lombok er, at det giver dig mulighed for at tilføje kommentarer til klasser, der automatisk genererer getters og settere, konstruktører, hashCode (), lige med(), og mere.

Når du er færdig, skal du se noget, der ligner figur 4.

Steven Haines

Trykker på Generer projekt vil udløse download af en zip-fil, der indeholder din projektkildekode. Pak den downloadede fil ud, og åbn den i din foretrukne IDE. Hvis du bruger IntelliJ, skal du vælge Fil og så Åben, og naviger til det bibliotek, hvor den downloadede zip-fil er blevet dekomprimeret.

Du finder ud af, at Spring Initializr har genereret to vigtige filer:

  1. En Maven pom.xml fil, som indeholder alle nødvendige afhængigheder til applikationen.
  2. BookserviceApplication.java, som er startklassen Spring Boot til applikationen.

Liste 1 viser indholdet af den genererede pom.xml-fil.

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