Ú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.