Guide til udskudt resultat i foråret

1. Oversigt

I denne vejledning ser vi på hvordan vi kan bruge Udskudt resultat klasse i Spring MVC for at udføre asynkron anmodning behandling.

Asynkron support blev introduceret i Servlet 3.0, og det er simpelt sagt muligt at behandle en HTTP-anmodning i en anden tråd end anmodningsmodtagertråden.

Udskudt resultat, tilgængelig fra foråret 3.2 og frem, hjælper med at aflaste en langvarig beregning fra en http-arbejdertråd til en separat tråd.

Selvom den anden tråd tager nogle ressourcer til beregning, er arbejdstrådene ikke blokeret i mellemtiden og kan håndtere indgående klientanmodninger.

Async-anmodningsbehandlingsmodellen er meget nyttig, da den hjælper med at skalere en applikation godt under høje belastninger, især til IO-intensive operationer.

2. Opsætning

For vores eksempler bruger vi en Spring Boot-applikation. For flere detaljer om, hvordan du bootstrap applikationen, henvises til vores forrige artikel.

Dernæst demonstrerer vi både synkron og asynkron kommunikation ved hjælp af Udskudt resultat og sammenlign også, hvor asynkron man skalerer bedre til tilfælde med høj belastning og IO-intensiv brug.

3. Blokering af REST-service

Lad os starte med at udvikle en standard blokerende REST-tjeneste:

@GetMapping ("/ proces-blokering") offentlig ResponseEntity handleReqSync (Model model) {// ... return ResponseEntity.ok ("ok"); }

Problemet her er, at anmodningens behandlingstråd er blokeret, indtil den komplette anmodning er behandlet og resultatet returneres. I tilfælde af langvarige beregninger er dette en suboptimal løsning.

For at løse dette kan vi gøre bedre brug af containertråde til at håndtere klientforespørgsler, som vi vil se i næste afsnit.

4. Ikke-blokerende REST ved hjælp Udskudt resultat

For at undgå blokering bruger vi callbacks-baseret programmeringsmodel, hvor vi i stedet for det faktiske resultat returnerer en Udskudt resultat til servletbeholderen.

@GetMapping ("/ async-deferredresult") offentlig DeferredResult handleReqDefResult (modelmodel) {LOG.info ("Modtaget anmodning om asynk-udskudt resultat"); Udskudt resultat output = nyt DeferredResult (); ForkJoinPool.commonPool (). Indsend (() -> {LOG.info ("Behandler i separat tråd"); prøv {Thread.sleep (6000);} fangst (InterruptedException e) {} output.setResult (ResponseEntity.ok ( "Okay")); }); LOG.info ("frigivet servlet-tråd"); returnere output; }

Behandling af anmodning sker i en separat tråd, og når den er afsluttet, påkalder vi setResult drift på Udskudt resultat objekt.

Lad os se på logoutputtet for at kontrollere, at vores tråde opfører sig som forventet:

[nio-8080-exec-6] com.baeldung.controller.AsyncDeferredResultController: Modtaget async-udskudt resultatanmodning [nio-8080-exec-6] com.baeldung.controller.AsyncDeferredResultController: Servlet-tråd frigivet [nio-8080-exec-6 ] java.lang.Tråd: Behandling i separat tråd

Internt meddeles containertråden, og HTTP-svaret leveres til klienten. Forbindelsen forbliver åben af ​​containeren (servlet 3.0 eller senere), indtil svaret ankommer eller timeout.

5. Udskudt resultat Tilbagekald

Vi kan registrere 3 typer tilbagekald med et udskudt resultat: afslutning, timeout og fejl tilbagekald.

Lad os bruge onCompletion () metode til at definere en blok af kode, der udføres, når en async-anmodning fuldføres:

deferredResult.onCompletion (() -> LOG.info ("Behandling afsluttet"));

På samme måde kan vi bruge onTimeout () at registrere brugerdefineret kode for at påberåbe sig, når timeout opstår. For at begrænse anmodningens behandlingstid kan vi overføre en timeout-værdi i løbet af Udskudt resultat objekt oprettelse:

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

I tilfælde af timeouts indstiller vi en anden svarstatus via timeout-handler, der er registreret hos Udskudt resultat.

Lad os udløse en timeout-fejl ved at behandle en anmodning, der tager mere end de definerede timeout-værdier på 5 sekunder:

ForkJoinPool.commonPool (). Indsend (() -> {LOG.info ("Behandler i separat tråd"); prøv {Thread.sleep (6000);} fangst (InterruptedException e) {...} deferredResult.setResult (ResponseEntity) .okay okay"))); });

Lad os se på logfiler:

[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 anmodning opstod

Der vil være scenarier, hvor langvarig beregning mislykkes på grund af en eller anden fejl eller undtagelse. I dette tilfælde kan vi også registrere en onError () ring tilbage:

deferredResult.onError ((Throwable t) -> {deferredResult.setErrorResult (ResponseEntity.status (HttpStatus.INTERNAL_SERVER_ERROR) .body ("Der opstod en fejl."))});

I tilfælde af en fejl, mens vi beregner svaret, indstiller vi en anden svarstatus og meddelelsesdel via denne fejlhåndterer.

6. Konklusion

I denne hurtige artikel så vi på, hvordan Spring MVC Udskudt resultat letter oprettelsen af ​​asynkrone slutpunkter.

Som sædvanlig er den komplette kildekode tilgængelig på Github.