Vodič za odgođeni rezultat u proljeće

1. Pregled

U ovom uputstvu ćemo pogledati kako možemo koristiti Odgođeni rezultat klase u Spring MVC za izvođenje asinkrone obrade zahtjeva.

Asinhrona podrška uvedena je u Servlet 3.0 i, jednostavno rečeno, omogućuje obradu HTTP zahtjeva u drugoj niti osim niti primatelja zahtjeva.

Odgođeni rezultat, dostupan od proljeća 3.2 nadalje, pomaže u rasterećenju dugotrajnog računanja iz niti http-worker u zasebnu nit.

Iako će druga nit uzeti neke resurse za izračunavanje, radne niti u međuvremenu nisu blokirane i mogu obrađivati ​​dolazne zahtjeve klijenta.

Model obrade asinkronog zahtjeva vrlo je koristan jer pomaže u dobroj skaliranju aplikacije tijekom velikih opterećenja, posebno za IO intenzivne operacije.

2. Postavljanje

Za naše primjere koristit ćemo aplikaciju Spring Boot. Za više detalja o pokretanju aplikacije pogledajte naš prethodni članak.

Dalje, demonstrirat ćemo i sinkronu i asinkronu komunikaciju pomoću Odgođeni rezultat i također usporediti kako se asinkroni skalira bolje za slučajeve intenzivnog korištenja s velikim opterećenjem i IO.

3. Blokiranje REST usluge

Počnimo s razvojem standardne usluge REST za blokiranje:

@GetMapping ("/ blokiranje procesa") javni ResponseEntity handleReqSync (model modela) {// ... return ResponseEntity.ok ("ok"); }

Ovdje je problem u tome nit obrade zahtjeva blokira se dok se ne obradi cjeloviti zahtjev i rezultat se vraća. U slučaju dugotrajnih izračunavanja, ovo je neoptimalno rješenje.

Da bismo to riješili, možemo bolje koristiti niti kontejnera za obradu zahtjeva klijenta, kao što ćemo vidjeti u sljedećem odjeljku.

4. Korištenje REST-a koji ne blokira Odgođeni rezultat

Da bismo izbjegli blokiranje, upotrijebit ćemo programski model zasnovan na povratnim pozivima, gdje ćemo umjesto stvarnog rezultata vratiti a Odgođeni rezultat u spremnik za servlet.

@GetMapping ("/ async-deferredresult") javni DeferredResult handleReqDefResult (model modela) {LOG.info ("Primljen async-deferredresult zahtjev"); Odgođeni rezultat izlaz = novi odgođeni rezultat (); ForkJoinPool.commonPool (). Submit (() -> {LOG.info ("Obrada u zasebnoj niti"); probajte {Thread.sleep (6000);} catch (InterruptedException e) {} output.setResult (ResponseEntity.ok ( "u redu")); }); LOG.info ("oslobođena nit servleta"); povratni izlaz; }

Obrada zahtjeva vrši se u zasebnoj niti i nakon dovršetka pozivamo na setResult operacija na Odgođeni rezultat objekt.

Pogledajmo izlaz iz dnevnika kako bismo provjerili ponašaju li se naše niti prema očekivanjima:

[nio-8080-exec-6] com.baeldung.controller.AsyncDeferredResultController: primljen async-deferredresult zahtjev [nio-8080-exec-6] com.baeldung.controller.AsyncDeferredResultController: Servlet-thread 6 freed [exec-n80] ] java.lang.Thred: Obrada u zasebnoj niti

Interno se nit kontejnera obavještava i HTTP odgovor dostavlja klijentu. Spremnik će ostati otvoren (servlet 3.0 ili noviji) sve dok odgovor ne stigne ili ne istekne.

5. Odgođeni rezultat Povratni pozivi

Pomoću DeferredResult možemo registrirati 3 vrste povratnih poziva: dovršavanje, vremensko ograničenje i povratne pogreške.

Iskoristimo onCompletion () metoda za definiranje bloka koda koji se izvršava kada se završi asinkroni zahtjev:

deferredResult.onCompletion (() -> LOG.info ("Obrada dovršena"));

Slično tome, možemo koristiti onTimeout () za registraciju prilagođenog koda za pozivanje nakon isteka vremena čekanja. Kako bismo ograničili vrijeme obrade zahtjeva, možemo dodati vrijednost vremenskog ograničenja tijekom Odgođeni rezultat stvaranje predmeta:

Odgođeni rezultat deferredResult = novi odgođeni rezultat (500l); deferredResult.onTimeout (() -> deferredResult.setErrorResult (ResponseEntity.status (HttpStatus.REQUEST_TIMEOUT) .body ("Došlo je do vremenskog ograničenja zahtjeva.))));

U slučaju vremenskih ograničenja, postavljamo drugačiji status odgovora putem obrađivača vremenskog ograničenja registriranog kod Odgođeni rezultat.

Potaknimo pogrešku vremenskog ograničenja obrađivanjem zahtjeva koji traje više od definiranih vrijednosti vremenskog ograničenja od 5 sekundi:

ForkJoinPool.commonPool (). Submit (() -> {LOG.info ("Obrada u zasebnoj niti"); pokušajte {Thread.sleep (6000);} catch (InterruptedException e) {...} deferredResult.setResult (ResponseEntity .ok ("U redu"))); });

Pogledajmo zapisnike:

[nio-8080-exec-6] com.baeldung.controller.DeferredResultController: oslobođena nit servleta [nio-8080-exec-6] java.lang.Thread: Obrada u zasebnoj niti [nio-8080-exec-6] com. baeldung.controller.DeferredResultController: Došlo je do vremenskog ograničenja zahtjeva

Bit će scenarija u kojima dugotrajno računanje ne uspije zbog neke pogreške ili iznimke. U ovom slučaju možemo registrirati i onError () uzvratiti poziv:

deferredResult.onError ((Throwable t) -> {deferredResult.setErrorResult (ResponseEntity.status (HttpStatus.INTERNAL_SERVER_ERROR) .body ("Dogodila se pogreška."));});

U slučaju pogreške, tijekom izračunavanja odgovora, postavljamo drugačiji status odgovora i tijelo poruke putem ovog obrađivača pogrešaka.

6. Zaključak

U ovom kratkom članku pogledali smo kako proljetni MVC Odgođeni rezultat olakšava stvaranje asinkronih krajnjih točaka.

Kao i obično, cjeloviti izvorni kod dostupan je na Githubu.


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