JavaRush /Курсхо /All lectures for TG purposes /Дархостҳои асинхронӣ

Дархостҳои асинхронӣ

All lectures for TG purposes
Сатҳи , Дарс
дастрас

Spring MVC бо коркарди асинхронии дархостҳо дар Servlet 3.0 васеъ муттаҳид шудааст:

  • Арзиши бозгашти DeferredResult ва Callable дар методҳои контроллер барои дастгирии як арзиши асинхронии бозгаштии асосӣ пешниҳод карда мешавад.

  • Контроллерҳо метавонанд чандин арзишро пайдарпай фиристанд, аз ҷумла SSE ва маълумоти хом.

  • Контроллерҳо метавонанд муштариёни реактивиро истифода баранд ва намуди реактивиро барои коркарди ҷавобҳо бозгардонанд.

DeferredResult

Вақте ки функсияи коркарди асинхронии дархостҳо дар контейнери сервлетҳо фаъол мешавад, методҳои контроллер метавонанд ҳар як арзиши бозгашти методи контроллерро бо истифодаи DeferredResult пӯшанд, чунон ки дар мисоли зерин нишон дода шудааст:

Java
@GetMapping("/quotes")
@ResponseBody
public DeferredResult<String> quotes() {
    DeferredResult<String> deferredResult = new DeferredResult<String>();
    // Аз ягон ҷараёни дигар...
    return deferredResult;
}
// deferredResult-ро ягон ҷо нигоҳ медорем...
deferredResult.setResult(result);
Kotlin
@GetMapping("/quotes")
@ResponseBody
fun quotes(): DeferredResult<String> {
    val deferredResult = DeferredResult<String>()
    // Аз ягон ҷараёни дигар...
    return deferredResult
}
// deferredResult-ро ягон ҷо нигоҳ медорем...
deferredResult.setResult(result)

Контроллер метавонад арзиши бозгаштро асинхронӣ, аз ҷараёни дигар гирифта – масалан, дар ҷавоб ба ҳодисаи берунӣ (пахши JMS), вазифаи муқарраршуда ё ҳодисаи дигар.

Callable

Контроллер метавонад ҳар як арзиши бозгаштиро бо истифодаи java.util.concurrent.Callable пӯшад, чунон ки дар мисоли зерин нишон дода шудааст:

Java
@PostMapping
public Callable<String> processUpload(final MultipartFile file) {
    return new Callable<String>() {
        public String call() throws Exception {
            // ...
            return "someView";
        }
    };
}
Kotlin
@PostMapping
fun processUpload(file: MultipartFile) = Callable<String> {
    // ...
    "someView"
}

Арзиши бозгаштро метавон бо иҷрои ин вазифа тавассути TaskExecutor, ки танзим шудааст, ба даст овард.

Коркард

Баъдан, коркарди асинхронии дархостҳои сервлетҳо мухтасар тасвир шудааст:

  • ServletRequest метавонад ба ҳолати асинхронӣ гузарад, бо даъвати request.startAsync(). Натичаи асосии ин он аст, ки сервлет (ва ҳар гуна филтрҳо) метавонанд иҷроишро анҷом диҳанд, аммо ҷавоб кушода мемонад, то ки коркард дертар анҷом ёбад.

  • Даъвати request.startAsync() AsyncContext-ро бозгардонида, ки онро барои назорати бештар бар арзёбии асинхронии коркарди дархост истифода бурдан мумкин аст. Масалан, он методи dispatch-ро пешбинӣ мекунад, ки ба пешрафти аз Servlet API монанд аст, ба истиснои он, ки ба барнома иҷозат медиҳад, ки коркарди дархостро дар ҷараёни контейнерҳои сервлетҳо идома диҳад.

  • ServletRequest дастрасӣ ба DispatcherType-и ҷории худро пешбинӣ мекунад, ки барои фарқ кардани коркарди дархости ибтидоӣ, паҳнкунии асинхронӣ, пешрафт ва дигар намудҳои диспетчерҳо истифода бурдан мумкин аст.

Коркарди DeferredResult чунин кор мекунад:

  • Контроллер DeferredResult-ро бозгардонида, онро дар ягон навбат ё рӯйҳати дар ёд нигоҳ дошта медонад, ки ба он дастрасӣ пайдо кардан мумкин аст.

  • Spring MVC request.startAsync()-ро даъват мекунад.

  • Дар ҳамин вақт, DispatcherServlet ва ҳама филтрҳои танзимшуда аз ҷараёни коркарди дархост мебароянд, аммо ҷавоб кушода мемонад.

  • Барнома DeferredResult-ро аз ягон ҷараён мегузорад, ва Spring MVC дархостро ба контейнерҳои сервлетҳо равон мекунад.

  • DispatcherServlet барои боз даъват карда мешавад, ва коркард бо истифодаи арзиши асинхронӣ бозгардонида мешавад.

Коркарди Callable чунин аст:

  • Контроллер Callable-ро бозгардонида мекунад.

  • Spring MVC request.startAsync()-ро даъват карда, Callable-ро ба TaskExecutor барои коркард дар ҷараёни алоҳида медиҳад.

  • Дар ҳамин вақт, DispatcherServlet ва ҳама филтрҳои контейнерҳои сервлетҳо аз ҷараён мебароянд, аммо ҷавоб кушода мемонад.

  • Дар натиҷа, Callable натиҷаро медиҳад, ва Spring MVC дархостро ба контейнерҳои сервлетҳо барои анҷоми коркарди дархост равон мекунад.

  • DispatcherServlet барои боз даъват карда мешавад, ва коркард бо истифодаи арзиши асинхронӣ аз Callable бозгардонида мешавад.

Барои маълумоти иловагӣ ва контекст, инчунин метавонед бо мақолаҳои блог шинос шавед, ки дар онҳо дастгирии асинхронӣ барои Spring MVC 3.2 пешниҳод шудааст.

Коркарди истисноҳо

Агар шумо DeferredResult-ро истифода баред, метавонед интихоб кунед, ки setResult ё setErrorResult бо истисно даъват кунед. Дар ҳар ду ҳолат, Spring MVC дархостро боз ба контейнерҳои сервлетҳо барои анҷоми коркарди дархост равон мекунад. Пас, он ба назар гирифта мешавад, чунон ки контроллер методи пурра баргардонидашуда ё истисноеро, ки ба назар гирифта шуда буд, баргардонида бошад. Пас, истисно аз механизми коркарди истисноҳои муқаррарӣ мегузарад (масалан, даъват кардани методҳои аннотирована @ExceptionHandler).

Вақте ки Callable истифода мешавад, мантиқи коркарди монанд амалӣ мешавад, аммо фарқи асосӣ дар он аст, ки арзиши баргардонии аз Callable мебарояд ё истисно дар он рух медиҳад.

Паҳншавӣ

Намунаҳои HandlerInterceptor метавонанд намуди AsyncHandlerInterceptor дошта бошанд, то даъвати бозгардонишударо ба дархости ибтидоӣ таъмин кунанд, ки асинхронӣ коркарди дархостро оғоз мекунад (ба ҷои postHandle ва afterCompletion).

Иҷрои HandlerInterceptor метавонад CallableProcessingInterceptor ё DeferredResultProcessingInterceptor-ро барои ҳамгироии амиқтар бо давраи ҳаёти дархости асинхронӣ бақайд гирад (масалан, барои коркарди ҳодисаи вақтгузарҳо). Барои маълумоти бештар ба AsyncHandlerInterceptor нигаред.

DeferredResult даъватҳои бозгардонро onTimeout(Runnable) ва onCompletion(Runnable) таъмин мекунад. Маълумоти бештарро дар javadoc оид ба DeferredResult бинед. Callable метавонад баWebAsyncTask иваз шавад, ки методҳои иловагиро барои вақти интизорӣ ва бозгардонӣ таъмин мекунад.

Дар муқоиса бо WebFlux

Servlet API аввалан барои иҷрои як гузариш дар занҷири "филтр-сервлет" тарҳрезӣ шудааст. Коркарди асинхронӣ, ки ба Servlet 3.0 илова шуда буд, ба барномаҳо иҷозат медиҳад, ки аз занҷири "филтр-сервлет" бароранд, аммо ҷавоб кушода мемонад, ки барои коркарди иловагии дертар. Дастгирии асинхронӣ дар Spring MVC аз ин механизми асосӣ сохта шудааст. Вақте ки контроллер DeferredResult-ро бозгардонад, занҷири "филтр-сервлет" ба анҷом мерасад, ва ҷараёни контейнерҳо озод карда мешаванд. Баъдтар, вақте ки DeferredResult танзим мешавад, фиристодани ASYNC ба амал меояд (ба ҳамон URL), ҳангоми ки контроллер боз ҷуфт мешавад, аммо ба ҷои даъвати, арзиши DeferredResult-ро (чунон ки контроллер онро бозгардонад) барои идомаи коркард истифода мебарад.

Ба муқобили ин, Spring WebFlux дар Servlet API сохта нашудааст ва ба чунин функсияи коркарди асинхронии дархостҳо эҳтиёҷ надорад, зеро асинхронӣ ба таври таърифӣ дастгирӣ мешавад. Коркарди асинхронӣ ба ҳама шартномаҳои фреймворк ворид шудааст ва дар ҳама марҳилаҳои коркарди дархост дастгирӣ мешавад.

Аз нуқтаи назари модели барномасозӣ, ҳам Spring MVC ва ҳам Spring WebFlux намуди асинхронӣ ва реактивӣ барои арзишҳои бозгашт дар методҳои контроллерро дастгирӣ мекунанд. Spring MVC ҳатто дастгирии пайдарпаи маълумотро, аз ҷумла аҳамияти реактивиро дастгирӣ мекунад. Аммо сабтҳои алоҳида дар ҷавоб мемонанд, ки маҳдуд мешаванд (ва дар ҷараёни алоҳида иҷро мешаванд), дар муқоиса бо WebFlux, ки ба ворид-барори номаҳдуд такя мекунад ва ба ҷараёни иловагӣ барои ҳар як сабт ниёз надорад.

Боз як фарқи асосӣ он аст, ки Spring MVC намуди асинхронӣ ё реактивиро дар параметрҳои методҳои контроллер (масалан, @RequestBody, @RequestPart ва дигарон), инчунин дастгирии возеҳ барои намуди асинхронӣ ва реактивӣ ҳамчун атрибутҳои моделиро дастгирӣ намекунад. Spring WebFlux ҳамаи инро дастгирӣ мекунад.

Пайдарпаии HTTP

Шумо метавонед DeferredResult ва Callable барои як арзиши асинхронӣ бозгардонишатон истифода баред. Чӣ мешавад, агар ба шумо лозим аст, ки якчанд арзишҳои асинхрониро бигиред ва онҳоро дар ҷавоб нависед? Дар ин қисмат тарзи иҷрои ин амал тавзеҳ дода шудааст.

Объектҳо

Шумо метавонед арзиши бозгардони ResponseBodyEmitter-ро барои эҷоди ҷараёни объектҳо истифода баред, ки ҳар яки онҳо бо истифодаи HttpMessageConverter сериализатсия мешаванд ва дар ҷавоб навишта мешаванд, чунон ки дар мисоли зерин нишон дода шудааст:

Java
@GetMapping("/events")
public ResponseBodyEmitter handle() {
    ResponseBodyEmitter emitter = new ResponseBodyEmitter();
    // Эмиттерро ягон ҷо нигоҳ медорем...
    return emitter;
}
// Дар ҷараёни дигар
emitter.send("Hello once");
// ва боз
emitter.send("Hello again");
// ва дар як лаҳза тайёр мешавад
emitter.complete();
Kotlin
@GetMapping("/events")
fun handle() = ResponseBodyEmitter().apply {
    // Эмиттерро ягон ҷо нигоҳ медорем...
}
// Дар ҷараёни дигар
emitter.send("Hello once")
// ва боз
emitter.send("Hello again")
// ва дар як лаҳза тайёр мешавад
emitter.complete()

Шумо инчунин метавонед ResponseBodyEmitter-ро ҳамчун ҷисми дар ResponseEntity истифода баред, ки ба шумо имконияти танзими статус ва сарлавҳаҳои ҷавобро медиҳад.

Вақте ки emitter IOException-ро (масалан, агар муштарии дурдаст нопадид шавад) тавлид мекунад, барномаҳо барои тоза кардани пайваст масъулият надоранд ва набояд бояд emitter.complete ё emitter.completeWithError даъват кунанд. Ба ҷои ин, контейнерҳои сервлетҳо автоматӣ огоҳиномаи хатоии AsyncListener-ро ифтитоҳ мекунанд, ки дар он Spring MVC низ completeWithError даъват мекунад. Ин даъват, дар навбати худ, фиристодани охирини ASYNC ба барнома анҷом медиҳад, дар ҳоле ки Spring MVC истиснонависро, ки конфигуратсия шудаанд, даъват мекунад ва дархостро хатм мекунад.

SSE

SseEmitter (зеркласси ResponseBodyEmitter) дастгирии Server-Sent Events, агар ҳодисаҳои фиристодаи сервер бо спецификаи W3C SSE мувофиқат кунанд. Барои эҷоди ҷараёни SSE аз контроллер, SseEmitter-ро бозгардонед, чунон ки дар мисоли зерин нишон дода шудааст:

Java
@GetMapping(path="/events", produces=MediaType.TEXT_EVENT_STREAM_VALUE)
public SseEmitter handle() {
    SseEmitter emitter = new SseEmitter();
    // Эмиттерро ягон ҷо нигоҳ медорем...
    return emitter;
}
// Дар ҷараёни дигар
emitter.send("Hello once");
// ва боз
emitter.send("Hello again");
// ва дар як лаҳза тайёр мешавад
emitter.complete();
Kotlin
@GetMapping("/events", produces = [MediaType.TEXT_EVENT_STREAM_VALUE])
fun handle() = SseEmitter().apply {
    // Эмиттерро ягон ҷо нигоҳ медорем...
}
// Дар ҷараёни дигар
emitter.send("Hello once")
// ва боз
emitter.send("Hello again")
// ва дар як лаҳза тайёр мешавад
emitter.complete()

Ҳарчанд SSE ва варианти асосӣ барои ҷараёни маълумот ба браузерҳо аст, дар назар доред, ки Internet Explorer ҳодисаҳои фиристодаи сервер (Server-Sent Events) -ро дастгирӣ намекунад. Истифодаи протоколи WebSocket аз Spring бо механизмҳои алтернативи паҳнкунии SockJS (аз ҷумла SSE) -ро, ки барои доираи васеи браузерҳо пешбинӣ шудааст, шояд баррасӣ кунед.

Маълумоти хом

Базӯрт дар баъзе ҳолатҳо ҳал кардан тавассути танзимоти паёмнависӣ гузароӣ кунад ва ҷараёни иттилоотро бевосита ба OutputStream ҷавоб диҳад (масалан, вақти боркунии файл). Барои интихоб кардан аз намуди бозгаштии StreamingResponseBody истифода бурдан мумкин аст, чунон ки дар мисоли зерин нишон дода шудааст:

Java
@GetMapping("/download")
public StreamingResponseBody handle() {
    return new StreamingResponseBody() {
        @Override
        public void writeTo(OutputStream outputStream) throws IOException {
            // навиштан...
        }
    };
}
Kotlin
@GetMapping("/download")
fun handle() = StreamingResponseBody {
    // навиштан...
}

Шумо метавонед StreamingResponseBody-ро ҳамчун ҷисми дар ResponseEntity истифода баред, ки ба шумо имконияти танзими статус ва сарлавҳаҳои ҷавобро медиҳад.

Намуди реактивӣ

Spring MVC истифодаи китобхонаҳои муштариёни реактивиро дар контроллер дастгирӣ мекунад. Аз ҷумла чунин китобхонаҳо WebClient аз spring-webflux ва дигарон, монанди репозиторҳои реактивии лоиҳаи Spring Data. Дар чунин сценариҳо қулай аст, ки намуди реактивиро аз методи контроллер бозгардонад.

Арзишҳои бозгашти реактивӣ чунин коркард мешаванд:

  • Промис бо як арзиши танзимшуда дар ҳолати истифодаи DeferredResult. Масалан, Mono (Reactor) ё Single (RxJava).

  • Ҷараёни бисёр арзишӣ бо навъи ҳуҷҷати таҳвили маълумоти ҷараёнӣ (масалан, application/x-ndjson ё text/event-stream) танзим мешавад, ба монанди истифодаи ResponseBodyEmitter ё SseEmitter. Масалан, Flux (Reactor) ё Observable (RxJava). Барномаҳо инчунин метавонанд Flux<ServerSentEvent> ё Observable<ServerSentEvent> баргардонанд.

  • Ҷараёни бисёр арзишӣ бо ҳар навъи дигари ҳуҷҷати таҳвили маълумот (масалан, application/json) танзим мешавад, ба монанди истифодаи DeferredResult<List<?>>.

Spring MVC Reactor ва RxJava-ро тавассути ReactiveAdapterRegistry аз spring-core дастгирӣ мекунад, ки ба он имкон медиҳад, ки ҳангоми гузариш байни якчанд китобхонаҳои реактивӣ танзим шавад.

Барои паҳнкунии иттилоот дар ҷавоб, реактивии бозгардонӣ дастгирӣ мешавад, аммо навиштан дар ҷавоб бо ҳамон манъ карда мешавад ва дар ҷараёни алоҳида тавассути AsyncTaskExecutor, ки конфигуратсия шудааст, иҷро мешавад, то манъ кардани манбаи ҷараёни болоӣ (масалан, Flux, ки аз WebClient баргардонида шудааст) пешгирӣ карда шавад. Бо танзимоти барқӣ истифодаи SimpleAsyncTaskExecutor аст, ки барои боргузорӣ мутобиқ нест. Агар ният дошта бошед, ки як чарх бо намуди реактивӣ истифодашаванда бошад, пас, танзимоти MVC-ро барои танзими иҷроишгар истифода намоед.

Пайвастшавии гумшуда

Servlet API ягон огоҳиномаи пайвастшавӣ намедиҳад, вақте ки муштарии дурдаст нопадид шавад. Аз ин рӯ, ҳангоми паҳн кардани ҷавоб, хоҳ бо истифодаи SseEmitter ё намуди реактивӣ, муҳим аст периодикӣ иттилоотро фиристед, зеро навиштан рӯй намедиҳад, агар муштарӣ пайваст нагашта бошадҳамон намешавад. Пахш метавонад шакли фурӯши холӣ (танҳо барои шарҳ) ё ҳама гуна маълумотҳои дигарро дошта бошад, ки тарафи дигар бояд онро ҳамчун паём ва дарк кунад ва онро нодида гирад.

Ғайр аз ин, шумо метавонед қарорҳои мубодилаи паёмҳои вебро истифода баред (масалан, STOMP бар болои WebSocket ё WebSocket бо SockJS), ки ҳамеша механизми интиқоли паём дар дохил доранд.

Танзимот

Функсияи коркарди асинхронии дархостҳо бояд дар сатҳи контейнерҳои сервлетҳо фаъол карда шавад. Таҳвили MVC инчунин якчанд имконоти барои дархостҳои асинхронӣ пешниҳод мекунад.

Контейнерҳои сервлетҳо

Эълонҳои филтрҳо ва сервлетҳо дорои флаги asyncSupported мебошанд, ки бояд ба true танзим карда шавад, ки коркарди асинхрониро фаъол мекунад. Ғайр аз ин, харгушҳои филтр бояд эълон карда шаванд, ки барои коркарди ASYNC javax.servlet.DispatchType.

Дар таҳвили, вақте, ки шумо AbstractAnnotationConfigDispatcherServletInitializer барои инициализатсияи контейнерҳои сервлетҳо истифода мекунед, ин амал автоматӣ иҷро мешавад.

Дар web.xml шумо метавонед <async-supported>true</async-supported> ба DispatcherServlet ва ба Filter декларатсияҳо илова кунед ва илова кунед <dispatcher>ASYNC</dispatcher> ба роҳандозкунии филтрҳо.

Spring MVC

Таҳвили MVC имконоти зеринро, ки ба коркарди асинхронӣ алоқаманданд, пешниҳод мекунад:

  • Таҳвили: Танзимоти configureAsyncSupport барои WebMvcConfigurer истифода кунед.

  • Фазои номҳои XML: Элементи <async-support> дар <mvc:annotation-driven> истифода кунед.

Шумо метавонед параметрҳои зеринро танзим кунед:

  • Арзиши вақти интизории стандартӣ барои дархостҳои асинхронӣ, ки агар танзим шавад, аз дастгоҳи контейнери сервлетҳо вобаста аст.

  • AsyncTaskExecutor барои истифодабарии навиштани бозгардонӣ ҳангоми пайдарпай бо намуди реактивӣ ва барои иҷрои намунаҳои Callable, ки аз методҳои контроллер бозгардонида мешаванд. Шадидан тавсия дода мешавад, ки ин хосиятро танзим кунед, агар шумо бо намуди реактивӣ кор кунед ё агар шумо методҳои контроллерро, ки Callable бозменамоянд, дошта бошед, зеро он аз рӯи танзим SimpleAsyncTaskExecutor аст.

  • Иҷрои DeferredResultProcessingInterceptor ва иҷрои CallableProcessingInterceptor.

Назар кунед, ки шумо инчунин метавонед арзиши вақти интизорӣ барои DeferredResult, ResponseBodyEmitter ва SseEmitter танзим кунед. Барои Callable шумо метавонед WebAsyncTask истифода баред, ки арзиши вақти интизориро нишон диҳед.

Шарҳҳо
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION