Útmutató a DeferredResult tavasszal

1. Áttekintés

Ebben az oktatóanyagban megnézzük hogyan tudjuk használni a Halasztott eredmény osztály tavaszi MVC-ben aszinkron kérelemfeldolgozás elvégzésére.

Az aszinkron támogatást a Servlet 3.0-ban vezették be, és egyszerűen fogalmazva lehetővé teszi a HTTP-kérelmek feldolgozását egy másik szálban, nem a kérés-vevő szálában.

DeferredResult, elérhető a 3.2 tavasztól, segíti a régóta futó számítások letöltését egy http-worker szálból egy külön szálba.

Bár a másik szál némi erőforrást igényel a számításhoz, a munkásszálak időközben nincsenek blokkolva, és képesek kezelni a bejövő ügyfélkéréseket.

Az async kérés-feldolgozási modell nagyon hasznos, mivel segít az alkalmazások méretezésében nagy terhelések esetén, különösen az IO intenzív műveleteknél.

2. Beállítás

Példaként a Spring Boot alkalmazást fogjuk használni. Az alkalmazás indításának módjáról az előző cikkünkben olvashat bővebben.

Ezután bemutatjuk a szinkron és az aszinkron kommunikációt egyaránt Halasztott eredmény és hasonlítsa össze azt is, hogy az aszinkron hogyan méretezhető jobban a nagy terhelésű és az IO intenzív használat esetén.

3. A REST szolgáltatás blokkolása

Kezdjük egy szabványos blokkoló REST szolgáltatás kifejlesztésével:

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

A probléma itt az a kérelem feldolgozási szála a teljes kérelem feldolgozásáig blokkolva van és az eredmény visszatér. Hosszan futó számítások esetén ez nem optimális megoldás.

Ennek megoldása érdekében jobban felhasználhatjuk a konténerszálakat az ügyfélkérelmek kezelésére, ahogy a következő szakaszban láthatjuk.

4. Nem blokkoló REST használata Halasztott eredmény

A blokkolás elkerülése érdekében visszahívás-alapú programozási modellt fogunk használni, ahol a tényleges eredmény helyett a-t adunk vissza Halasztott eredmény a tálalótálcára.

@GetMapping ("/ async-deferredresult") public DeferredResult handleReqDefResult (modellmodell) {LOG.info ("Fogadott async-deferredresult kérés"); Halasztott eredmény output = new DeferredResult (); ForkJoinPool.commonPool (). Subm (() -> {LOG.info ("Feldolgozás külön szálban"); próbálja ki a {Thread.sleep (6000);} catch (InterruptedException e) {} output.setResult (ResponseEntity.ok ( "rendben")); }); LOG.info ("kiszolgáló szál felszabadult"); visszatérő kimenet; }

A kérelem feldolgozása külön szálban történik, és a befejezés után meghívjuk a setResult művelet a Halasztott eredmény tárgy.

Nézzük meg a napló kimenetét, hogy ellenőrizzük, hogy szálaink a várt módon viselkednek-e:

[nio-8080-exec-6] com.baeldung.controller.AsyncDeferredResultController: Fogadott async-deferredresult kérelem [nio-8080-exec-6] com.baeldung.controller.AsyncDeferredResultController: Servlet szál felszabadítva [nio-8080-exec-8080 ] java.lang.Thread: Feldolgozás külön szálban

Belsőleg értesítik a tárolószálat, és a HTTP-választ eljuttatják az ügyfélhez. A kapcsolat a tároló (3.0 vagy újabb szervlet) által nyitva marad, amíg a válasz meg nem érkezik, vagy elévül.

5. Halasztott eredmény Visszahívások

3 visszahívási típust regisztrálhatunk a DeferredResult segítségével: befejezés, időkorlát és hiba visszahívások.

Használjuk a onCompletion () módszer aszinkron kérés befejezésekor végrehajtott kódblokk definiálására:

deferredResult.onCompletion (() -> LOG.info ("Feldolgozás befejeződött"));

Hasonlóképpen használhatjuk onTimeout () egyéni kód regisztrálása az időkorlát bekövetkezése után. A kérelem feldolgozási idejének korlátozása érdekében átadhatunk egy időtúllépési értéket a Halasztott eredmény objektum létrehozása:

Halasztott eredmény deferredResult = új DeferredResult (500l); deferredResult.onTimeout (() -> deferredResult.setErrorResult (ResponseEntity.status (HttpStatus.REQUEST_TIMEOUT) .body ("A kérelem időtúllépés történt.")));

Időkorlátok esetén más válaszállapotot állítunk be a regisztrált időtúllépés-kezelőn keresztül Halasztott eredmény.

Indítsunk el időtúllépési hibát egy olyan kérés feldolgozásával, amely meghaladja a megadott 5 másodperces időtúllépési értéket:

ForkJoinPool.commonPool (). Subm (() -> {LOG.info ("Feldolgozás külön szálban"); próbálja ki a {Thread.sleep (6000);} catch (InterruptedException e) {...} deferredResult.setResult (ResponseEntity) .oké oké"))); });

Nézzük meg a naplókat:

[nio-8080-exec-6] com.baeldung.controller.DeferredResultController: kiszolgáló szál felszabadította [nio-8080-exec-6] java.lang.Thread: Feldolgozás külön szálban [nio-8080-exec-6] com. baeldung.controller.DeferredResultController: A kérelem időtúllépése megtörtént

Lesznek olyan esetek, amikor a hosszú ideig tartó számítás valamilyen hiba vagy kivétel miatt meghiúsul. Ebben az esetben regisztrálhatunk egy onError () visszahív:

deferredResult.onError ((Throwable t) -> {deferredResult.setErrorResult (ResponseEntity.status (HttpStatus.INTERNAL_SERVER_ERROR) .body ("Hiba történt."));});

Hiba esetén, a válasz kiszámítása közben, ezzel a hibakezelővel más válaszállapotot és üzenettestet állítunk be.

6. Következtetés

Ebben a gyors cikkben megnéztük, hogy a tavaszi MVC Halasztott eredmény megkönnyíti az aszinkron végpontok létrehozását.

Szokás szerint a teljes forráskód elérhető a Githubon.