Spring Boot Webflux uchun autokonfiguratsiyani ta'minlab, reaktiv veb-ilovalarni ishlab chiqishni osonlashtiradi.
"Spring WebFlux" frameworki
Spring WebFlux - bu Spring Framework 5.0 da taqdim etilgan yangi reaktiv veb-framework. Spring MVC dan farqli o'laroq, u servlet API larining mavjudligini talab qilmaydi, to'liq asinxron va blokirovka qilinmaydigan hamda Reactive Streams spetsifikatsiyasini Reactor loyihasi orqali amalga oshiradi.
Spring WebFlux ikki variantda keladi: funksional modelga asoslangan va annotatsiyalar asosida. Annotatsiyalarga asoslangan model Spring MVC modeliga juda yaqin, quyidagi misolda ko'rsatilgandek:
@RestController @RequestMapping("/users") public class MyRestController { private final UserRepository userRepository; private final CustomerRepository customerRepository; public MyRestController(UserRepository userRepository, CustomerRepository customerRepository) { this.userRepository = userRepository; this.customerRepository = customerRepository; } @GetMapping("/{userId}") public Mono<User> getUser(@PathVariable Long userId) { return this.userRepository.findById(userId); } @GetMapping("/{userId}/customers") public Flux<Customer> getUserCustomers(@PathVariable Long userId) { return this.userRepository.findById(userId).flatMapMany(this.customerRepository::findByUser); } @DeleteMapping("/{userId}") public Mono<Void> deleteUser(@PathVariable Long userId) { return this.userRepository.deleteById(userId); } }
@RestController @RequestMapping("/users") class MyRestController(private val userRepository: UserRepository, private val customerRepository: CustomerRepository) { @GetMapping("/{userId}") fun getUser(@PathVariable userId: Long): Mono<User?> { return userRepository.findById(userId) } @GetMapping("/{userId}/customers") fun getUserCustomers(@PathVariable userId: Long): Flux<Customer> { return userRepository.findById(userId).flatMapMany { user: User? -> customerRepository.findByUser(user) } } @DeleteMapping("/{userId}") fun deleteUser(@PathVariable userId: Long): Mono<Void> { return userRepository.deleteById(userId) } }
"WebFlux.fn", funksional modelga asoslangan variant, marshrutlash konfiguratsiyasini haqiqiy so'rovlarni qayta ishlashdan ajratadi, quyidagi misolda ko'rsatilgandek:
@Configuration(proxyBeanMethods = false) public class MyRoutingConfiguration { private static final RequestPredicate ACCEPT_JSON = accept(MediaType.APPLICATION_JSON); @Bean public RouterFunction<ServerResponse> monoRouterFunction(MyUserHandler userHandler) { return route() .GET("/{user}", ACCEPT_JSON, userHandler::getUser) .GET("/{user}/customers", ACCEPT_JSON, userHandler::getUserCustomers) .DELETE("/{user}", ACCEPT_JSON, userHandler::deleteUser) .build(); } }
@Configuration(proxyBeanMethods = false) class MyRoutingConfiguration { @Bean fun monoRouterFunction(userHandler: MyUserHandler): RouterFunction<ServerResponse> { return RouterFunctions.route( GET("/{user}").and(ACCEPT_JSON), userHandler::getUser).andRoute( GET("/{user}/customers").and(ACCEPT_JSON), userHandler::getUserCustomers).andRoute( DELETE("/{user}").and(ACCEPT_JSON), userHandler::deleteUser) } companion object { private val ACCEPT_JSON = accept(MediaType.APPLICATION_JSON) } }
@Component public class MyUserHandler { public Mono<ServerResponse> getUser(ServerRequest request) { ... } public Mono<ServerResponse> getUserCustomers(ServerRequest request) { ... } public Mono<ServerResponse> deleteUser(ServerRequest request) { ... } }
@Component class MyUserHandler { fun getUser(request: ServerRequest?): Mono<ServerResponse> { return ServerResponse.ok().build() } fun getUserCustomers(request: ServerRequest?): Mono<ServerResponse> { return ServerResponse.ok().build() } fun deleteUser(request: ServerRequest?): Mono<ServerResponse> { return ServerResponse.ok().build() } }
RouterFunction beanlarini aniqlashingiz mumkin. Agar bajarilishini ketma-ketlikda amalga oshirishni talab qilsangiz, beanlarda tartibni belgilash mumkin.
Ishni boshlash uchun spring-boot-starter-webflux modulini ilovangizga qo'shing.
spring-boot-starter-web va
spring-boot-starter-webflux modullari qo'shilsa, Spring Boot Spring MVC ni, emas WebFlux ni avtomatik ravishda konfigurlaydi. Bu ko'plab Spring ishlab chiquvchilar o'z Spring MVC ilovalari ichida reaktiv
WebClient ni ishlatish uchun
spring-boot-starter-webflux ni qo'shishgani uchun tanlangan. Siz hali ham o'zingizning ilova turini
SpringApplication.setWebApplicationType(WebApplicationType.REACTIVE) ga o'rnatib tanlashingiz mumkin.
Spring WebFlux autokonfiguratsiyasi
Spring Boot ko'p ilovalar bilan yaxshi ishlaydigan Spring WebFlux uchun autokonfiguratsiyani ta'minlaydi.
Autokonfiguratsiya Spring ning standart sozlamalariga quyidagi funksiyalarni qo'shadi:
-
HttpMessageReadervaHttpMessageWriterning misollari uchun kodek konfiguratsiyasi. -
Statik resurslarni qo'llab-quvvatlash vositalari, WebJar uchun qo'llab-quvvatlash vositalarini o'z ichiga oladi.
Agar siz Spring Boot WebFlux ni qo'llab-quvvatlash imkoniyatlarini saqlab qolishni va qo'shimcha WebFlux konfiguratsiyasini qo'shishni xohlasangiz, o'z anotatsiyalangan @Configuration sinfingizni WebFluxConfigurer turidagi qo'shishingiz mumkin, ammo holda @EnableWebFlux anotatsiyasiz.
Siz Spring WebFlux ni to'liq nazorat qilishni xohlasangiz, o'z @Configuration ni qo'shishingiz va @EnableWebFlux bilan anotatsiya qilishingiz mumkin.
HTTP kodeklari orqali HttpMessageReaders va HttpMessageWriters
Spring WebFlux HTTP so'rovlarini va javoblarini o'zgartirish uchun HttpMessageReader va HttpMessageWriter interfeyslari ishlatadi. Ular CodecConfigurer yordamida sizning classpath dagi mavjud kutubxonalarni ko'rib chiqish orqali mos qiymatlar bilan ko'rsatiladi.
Spring Boot kodeklar uchun maxsus konfiguratsion xususiyatlar spring.codec.* taqdim etadi. Framework shuningdek, CodecCustomizer misollari orqali yanada moslashtirilgan sozlashni amalga oshiradi. Masalan, spring.jackson.* konfiguratsion kalitlari Jackson kutubxonasi kodekiga qo'llaniladi.
Agar kodeklarni qo'shish yoki sozlash kerak bo'lsa, quyidagi misolda ko'rsatilgandek maxsus CodecCustomizer komponentini yaratishingiz mumkin:
@Configuration(proxyBeanMethods = false) public class MyCodecsConfiguration { @Bean public CodecCustomizer myCodecCustomizer() { return (configurer) -> { configurer.registerDefaults(false); configurer.customCodecs().register(new ServerSentEventHttpMessageReader()); // ... }; } }
class MyCodecsConfiguration { @Bean fun myCodecCustomizer(): CodecCustomizer { return CodecCustomizer { configurer: CodecConfigurer -> configurer.registerDefaults(false) configurer.customCodecs().register(ServerSentEventHttpMessageReader()) } } }
Bundan tashqari, Spring Boot da maxsus JSON serializatorlar va deserializatorlardan foydalanishingiz mumkin.
Statik kontent
By default, Spring Boot classpath da /static (yoki /public, yoki /resources, yoki /META-INF/resources) kataloglaridan statik kontentni boshqaradi. Framework Spring WebFlux dan ResourceWebHandler ni ishlatadi, shuning uchun siz o'z WebFluxConfigurer xususiyatini qo'shib, addResourceHandlers metodini qayta belgilash orqali bunday ishlash mantiqini o'zgartirishingiz mumkin.
Asosan, resurslar /** da ko'rsatiladi, ammo siz bu mappingni nozik sozlashingiz mumkin, spring.webflux.static-path-pattern xususiyatini o'rnatib. Masalan, barcha resurslarni /resources/** ga ko'chirish quyidagicha amalga oshirilishi mumkin:
spring.webflux.static-path-pattern=/resources/**
spring:
webflux:
static-path-pattern: "/resources/**"
Bundan tashqari, spring.web.resources.static-locations yordamida statik resurslar joylashuvlarini sozlashingiz mumkin. Bunday holda, standart qiymatlar katalog joylashuvlarining ro'yxati bilan almashtiriladi. Bunday sozlamalar bilan standart home page ni aniqlash vositasi sizning maxsus joylashuvlaringizga o'tadi. Agar sizning joylashuvlaringizdan birortasida index.html mavjud bo'lsa, u holda bu ilovaning asosiy sahifasi bo'ladi.
Ilovaning statik resurslari uchun "standart" joylashuvlaridan tashqari, Webjars kontenti uchun maxsus stsenariy mavjud. /webjars/** yo'liga ega bo'lgan barcha resurslar, agar ular Webjars formatida qadoqlangan bo'lsa, jar fayllardan boshqariladi.
src/main/webapp katalogidan foydalanmaydi.
Bosh sahifa
Spring Boot statik ham, shablonli boshlang'ich sahifalarni qo'llab-quvvatlaydi. Framework birinchi bo'lib statik kontent joylashuvlarida index.html faylini izlaydi. Agar bunday shablon topilmasa, u index shablonini izlaydi. Agar ulardan biri topilsa, ilovaning asosiy sahifasi sifatida avtomatik ravishda ishlatiladi.
Shablonizatorlar
REST veb-xizmatlariga qo'shimcha ravishda, Spring WebFlux dinamik HTML kontentini boshqarish uchun ham ishlatilishi mumkin. Spring WebFlux turli xil shablonlash texnologiyalarini qo'llab-quvvatlaydi, jumladan Thymeleaf, FreeMarker va Mustache.
Spring Boot quyidagi shablonizatorlar uchun autokonfiguratsiyani qo'llab-quvvatlaydi:
Agar ushbu shablonizatorlardan biri standart konfiguratsiya bilan ishlatilsa, shablonlar avtomatik ravishda src/main/resources/templates dan tanlanadi.
Xatolarni qayta ishlash
Spring Boot barcha xatolarni to'g'ri qayta ishlaydigan WebExceptionHandler ni ta'minlaydi. Uning tartibi WebFlux tomonidan taqdim etilgan qayta ishlashdan oldin turadi. Mashina mijozlari uchun u xatolarni batafsil tavsifi, HTTP holat kodi va istisno xabari bilan JSON formatida javob yaratadi. Brauzer mijozlari uchun esa, HTML formatdagi ma'lumotlarni ko'rsatadigan "whitelabel" xato qayta ishlovchisi mavjud. Bundan tashqari, xatolar ekranida ko'rsatiladigan o'z HTML shablonlarini taqdim etish mumkin.
Ushbu funksiyani sozlashning birinchi bosqichi ko'pincha mavjud mexanizmni saqlashni, faqat xato kontentini qo'shish yoki almashtirishni o'z ichiga oladi. Buning uchun siz ErrorAttributes turini aniqlashni qo'shishingiz mumkin.
Xatolarni qayta ishlash mantiqini o'zgartirish uchun ErrorWebExceptionHandler ni amalga oshirishingiz va ushbu turdagi bean aniqlashni ro'yxatdan o'tkazishingiz mumkin. ErrorWebExceptionHandler juda quyi darajadagi bo'lganligi sababli, Spring Boot WebFlux orqali funksional tarzda xatolarni boshqarishga imkon beradigan AbstractErrorWebExceptionHandler yordamchisini ham taqdim etadi, quyidagi misolda ko'rsatilgandek:
@Component public class MyErrorWebExceptionHandler extends AbstractErrorWebExceptionHandler { public MyErrorWebExceptionHandler(ErrorAttributes errorAttributes, Resources resources, ApplicationContext applicationContext) { super(errorAttributes, resources, applicationContext); } @Override protected RouterFunction<ServerResponse> getRoutingFunction(ErrorAttributes errorAttributes) { return RouterFunctions.route(this::acceptsXml, this::handleErrorAsXml); } private boolean acceptsXml(ServerRequest request) { return request.headers().accept().contains(MediaType.APPLICATION_XML); } public Mono<ServerResponse> handleErrorAsXml(ServerRequest request) { BodyBuilder builder = ServerResponse.status(HttpStatus.INTERNAL_SERVER_ERROR); // ... mavjud bo'lgan qatorlarni qo'shish return builder.build(); } }
@Component class MyErrorWebExceptionHandler(errorAttributes: ErrorAttributes?, resources: WebProperties.Resources?, applicationContext: ApplicationContext?) : AbstractErrorWebExceptionHandler(errorAttributes, resources, applicationContext) { override fun getRoutingFunction(errorAttributes: ErrorAttributes): RouterFunction<ServerResponse> { return RouterFunctions.route(this::acceptsXml, this::handleErrorAsXml) } private fun acceptsXml(request: ServerRequest): Boolean { return request.headers().accept().contains(MediaType.APPLICATION_XML) } fun handleErrorAsXml(request: ServerRequest?): Mono<ServerResponse> { val builder = ServerResponse.status(HttpStatus.INTERNAL_SERVER_ERROR) // ... mavjud bo'lgan qatorlarni qo'shish return builder.build() } }
Ko'proq to'liq tasvir olish uchun DefaultErrorWebExceptionHandler ni to'g'ridan-to'g'ri subclass qilib, alohida metodlarni qayta belgilashingiz mumkin.
Ba'zi hollarda, nazoratchi yoki handler funksiyasi darajasida qayta ishlangan xatolar metrikalar infratuzilmasi tomonidan qayd etilmaydi. Ilovalar bunday istisnolarni so'rov metrikalariga yozishni ta'minlashi mumkin, agar ular qayta ishlangan istisnoni so'rov atributi sifatida o'rnatishsa:
@Controller public class MyExceptionHandlingController { @GetMapping("/profile") public Rendering userProfile() { // ... throw new IllegalStateException(); } @ExceptionHandler(IllegalStateException.class) public Rendering handleIllegalState(ServerWebExchange exchange, IllegalStateException exc) { exchange.getAttributes().putIfAbsent(ErrorAttributes.ERROR_ATTRIBUTE, exc); return Rendering.view("errorView").modelAttribute("message", exc.getMessage()).build(); } }
@Controller class MyExceptionHandlingController { @GetMapping("/profile") fun userProfile(): Rendering { // ... throw IllegalStateException() } @ExceptionHandler(IllegalStateException::class) fun handleIllegalState(exchange: ServerWebExchange, exc: IllegalStateException): Rendering { exchange.attributes.putIfAbsent(ErrorAttributes.ERROR_ATTRIBUTE, exc) return Rendering.view("errorView").modelAttribute("message", exc.message ?: "").build() } }
Maxsus xato sahifalari
Agar belgilangan holat kodi uchun maxsus HTML xato sahifasini chiqarish kerak bo'lsa, /error katalogidagi faylni qo'shishingiz mumkin. Xato sahifalari statik HTML (ya'ni statik resurs katalogidan biriga qo'shilgan) yoki shablonlar yordamida yaratilgan bo'lishi mumkin. Fayl nomi aniq holat kodi yoki seriya maskasiga to'g'ri kelishi kerak.
Masalan, 404 ni statik HTML fayli yordamida ko'rsatish uchun kataloglar strukturasi quyidagicha bo'lishi kerak:
src/
+- main/
+- java/
| + <source code>
+- resources/
+- public/
+- error/
| +- 404.html
+- <other public assets>
Barcha 5xx xatolarni Mustache shabloni yordamida ko'rsatish uchun kataloglar strukturasi quyidagicha bo'lishi kerak:
src/
+- main/
+- java/
| + <source code>
+- resources/
+- templates/
+- error/
| +- 5xx.mustache
+- <other templates>
Veb-filtrlar
Spring WebFlux HTTP so'rov va javoblar almashuvini filtrlash uchun amalga oshirilishi mumkin bo'lgan WebFilter interfeysini taqdim etadi. Ilova kontekstida topilgan WebFilter beanlari har bir almashuv holatini filtrlash uchun avtomatik ravishda ishlatiladi.
Agar filtrlarning tartibi muhim bo'lsa, ular Ordered sinfini amalga oshirishlari yoki @Order bilan belgilanadigan bo'lishi mumkin. Spring Boot autokonfiguratsiyasi veb-filtrlarni siz uchun sozlashi mumkin. Bunday holda, quyidagi jadvalda ko'rsatilgan tartibdan foydalaniladi:
| Veb-filter | Tartib |
|---|---|
|
|
|
|
|
|
|
|
|
GO TO FULL VERSION