Guide to DeferredResult in Spring

1. Oversikt

I denne opplæringen vil vi se på hvordan vi kan bruke Utsatt resultat klasse i vår MVC for å utføre asynkron behandling av forespørsler.

Asynkron støtte ble introdusert i Servlet 3.0, og rett og slett tillater det behandling av en HTTP-forespørsel i en annen tråd enn mottakertråden for forespørselen.

Utsatt resultat, tilgjengelig fra våren 3.2 og fremover, hjelper til med å laste ned en langvarig beregning fra en http-arbeidertråd til en egen tråd.

Selv om den andre tråden tar noen ressurser for beregning, er ikke arbeidertrådene blokkert i mellomtiden og kan håndtere innkommende klientforespørsler.

Behandlingsmodellen for async-forespørsler er veldig nyttig, da den hjelper til med å skalere en applikasjon godt under høye belastninger, spesielt for IO-intensive operasjoner.

2. Oppsett

For eksemplene våre bruker vi en Spring Boot-applikasjon. For mer informasjon om hvordan du starter opp applikasjonen, se vår forrige artikkel.

Deretter demonstrerer vi både synkron og asynkron kommunikasjon ved hjelp av UtsattResultat og sammenlign også hvor asynkron man skalerer bedre for høy belastning og IO-intensiv bruk.

3. Blokkering av REST-tjenesten

La oss starte med å utvikle en standard blokkerende REST-tjeneste:

@GetMapping ("/ process-blocking") public ResponseEntity handleReqSync (Model model) {// ... return ResponseEntity.ok ("ok"); }

Problemet her er at tråden for forespørselsbehandling er blokkert til hele forespørselen er behandlet og resultatet blir returnert. Ved langvarige beregninger er dette en suboptimal løsning.

For å løse dette kan vi bruke containertråder bedre til å håndtere klientforespørsler, som vi vil se i neste avsnitt.

4. Ikke-blokkerende REST ved bruk Utsatt resultat

For å unngå blokkering, bruker vi tilbakekallingsbasert programmeringsmodell, der vi i stedet for det faktiske resultatet returnerer en Utsatt resultat til servletbeholderen.

@GetMapping ("/ async-deferredresult") offentlig DeferredResult handleReqDefResult (modellmodell) {LOG.info ("Mottatt forespørsel om asynk-utsatt resultat"); Utsatt resultat output = new DeferredResult (); ForkJoinPool.commonPool (). Submit (() -> {LOG.info ("Processing in separate thread"); prøv {Thread.sleep (6000);} catch (InterruptedException e) {} output.setResult (ResponseEntity.ok ( "ok"));}); LOG.info ("servlet thread freed"); retur utgang; }

Behandling av forespørsel gjøres i en egen tråd og når den er fullført påkaller vi setResult drift på Utsatt resultat gjenstand.

La oss se på loggutgangen for å kontrollere at trådene våre oppfører seg som forventet:

[nio-8080-exec-6] com.baeldung.controller.AsyncDeferredResultController: Mottatt async-utsatt resultatforespørsel [nio-8080-exec-6] com.baeldung.controller.AsyncDeferredResultController: Servlet thread freed [nio-8080-exec-6 ] java.lang.Tråd: Behandler i egen tråd

Internt blir containertråden varslet, og HTTP-svaret blir levert til klienten. Forbindelsen forblir åpen av containeren (servlet 3.0 eller senere) til svaret kommer eller tidsavbrudd.

5. Utsatt resultat Tilbakekallinger

Vi kan registrere tre typer tilbakeringinger med et utsatt resultat: fullføring, tidsavbrudd og feilanrop.

La oss bruke onCompletion () metode for å definere en blokk med kode som utføres når en async-forespørsel fullføres:

deferredResult.onCompletion (() -> LOG.info ("Behandlingen fullført"));

På samme måte kan vi bruke onTimeout () å registrere egendefinert kode for å påkalle når timeout oppstår. For å begrense behandlingstid for forespørsler, kan vi sende en timeout-verdi i løpet av Utsatt resultat objektoppretting:

Utsatt resultat deferredResult = new DeferredResult (500l); deferredResult.onTimeout (() -> deferredResult.setErrorResult (ResponseEntity.status (HttpStatus.REQUEST_TIMEOUT) .body ("Request timeout occurred.")));

Ved tidsavbrudd setter vi en annen svarstatus via timeoutbehandler som er registrert hos UtsattResultat.

La oss utløse en tidsavbruddsfeil ved å behandle en forespørsel som tar mer enn de definerte tidsavbruddsverdiene på 5 sekunder:

ForkJoinPool.commonPool (). Send (() -> {LOG.info ("Processing in separate thread"); prøv {Thread.sleep (6000);} catch (InterruptedException e) {...} deferredResult.setResult (ResponseEntity .ok ("OK"))); });

La oss se på loggene:

[nio-8080-exec-6] com.baeldung.controller.DeferredResultController: servlet thread freed [nio-8080-exec-6] java.lang.Tråd: Behandling i separat tråd [nio-8080-exec-6] com. baeldung.controller.DeferredResultController: Timeout for forespørsel skjedde

Det vil være scenarier der langvarig beregning mislykkes på grunn av feil eller unntak. I dette tilfellet kan vi også registrere en onError () Ring tilbake:

deferredResult.onError ((Throwable t) -> {deferredResult.setErrorResult (ResponseEntity.status (HttpStatus.INTERNAL_SERVER_ERROR) .body ("Det oppstod en feil."))});

I tilfelle en feil, mens vi beregner svaret, setter vi en annen responsstatus og meldingsdel via denne feilbehandleren.

6. Konklusjon

I denne raske artikkelen så vi på hvordan Spring MVC UtsattResultat letter etableringen av asynkrone sluttpunkter.

Som vanlig er den komplette kildekoden tilgjengelig på Github.


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