Reactive programming ichiga quyidagilar kiradi: Project Reactor, Mono, Flux, Spring WebFlux, Reactive Streams spec, R2DBC, Virtual threads vs reactive trade-offs.
1. Reactive programming nima?
Reactive programming - data oqimi va async eventlar bilan ishlash usuli.
Oddiy qilib:
Request keldi, lekin thread kutib o‘tirmaydi. DB, HTTP yoki file javobini kutish paytida thread bo‘shab, boshqa ishni qiladi.
Traditional blocking model:
Request
↓
Thread ajratiladi
↓
DB javobini kutadi
↓
HTTP javobini kutadi
↓
Response qaytaradiReactive model:
Request
↓
Thread ishni boshlaydi
↓
DB/HTTP kutish paytida thread band bo‘lmaydi
↓
Javob kelganda callback/pipeline davom etadi
↓
Response qaytariladiReactive programming ayniqsa I/O-heavy tizimlarda foydali:
ko‘p HTTP call;
ko‘p DB call;
messaging;
streaming;
websocket;
real-time notification;
gateway;
chat;
live dashboard.
Lekin reactive programming har doim ham kerak emas.
2. Blocking vs Non-blocking
Blocking
Blocking degani: thread javob kelguncha kutib turadi.
User user = userRepository.findById(id);
Order order = orderClient.getOrder(user.getId());
return order;Bu kod oddiy va tushunarli. Lekin findById yoki getOrder vaqtida thread band bo‘lib turadi.
Masalan:
Thread 1 → DB javobini kutyapti
Thread 2 → Payment API kutyapti
Thread 3 → Redis kutyaptiThread ishlamayapti, lekin band.
Non-blocking
Non-blocking degani: thread kutib turmaydi. Javob kelganda pipeline davom etadi.
return userRepository.findById(id)
.flatMap(user -> orderClient.getOrder(user.getId()));Bu yerda method darhol Mono<Order> qaytaradi. Real natija keyinroq keladi.
3. Reactive programming qachon kerak?
Reactive yaxshi tanlov bo‘lishi mumkin, agar:
Ko‘p concurrent connection bor
Ko‘p tashqi API chaqiriladi
Thread kutib qolishi ko‘p
Streaming kerak
WebSocket kerak
Gateway yoki proxy yozilyapti
Latency va resource efficiency muhimMasalan API Gateway:
Client → Gateway → 10 ta backend serviceGateway ko‘p requestni ushlab turadi. Har request uchun platform thread band bo‘lsa, threadlar tez tugaydi. Reactive gateway bu yerda foydali.
4. Reactive qachon kerak emas?
Reactive har joyga qo‘yiladigan "zamonaviy bezak" emas.
Kerak bo‘lmasligi mumkin, agar:
Oddiy CRUD app
Team reactive’ni yaxshi bilmaydi
DB driver blocking bo‘lsa
Business logic CPU-heavy bo‘lsa
Debugging soddaligi muhim bo‘lsa
Virtual threads yetarli bo‘lsaAgar app asosan PostgreSQL bilan oddiy CRUD qilsa, Spring MVC + virtual threads yoki oddiy thread pool ko‘pincha yetarli.
5. Reactive Streams spec
Reactive Streams - JVM’da async stream processing uchun standart.
U 4 ta asosiy interface beradi:
Publisher<T>
Subscriber<T>
Subscription
Processor<T, R>Publisher
Data chiqaruvchi.
Men data yuboraman.Subscriber
Data qabul qiluvchi.
Men data olaman.Subscription
Subscriber qancha data xohlashini bildiradi.
Menga 10 ta item yubor.Processor
Ham subscriber, ham publisher.
Data olaman, o‘zgartiraman, keyin chiqaraman.Reactive Streams’ning eng muhim g‘oyasi:
Consumer qancha ko‘tara olsa, shuncha data oladi.
Bu backpressure deyiladi.
6. Backpressure
Backpressure - consumer producerga: "sekinroq yubor, men ulgurmayapman" deb signal berishi.
Masalan:
Producer: 10 000 item/sec
Consumer: 1 000 item/secAgar backpressure bo‘lmasa:
Queue to‘ladi
Memory oshadi
Latency oshadi
App yiqiladiReactive Streams’da subscriber qancha item olishni so‘raydi:
request(10)Ya’ni producer 10 ta yuboradi, keyin yana ruxsat kutadi.
7. Project Reactor
Project Reactor - Spring ekotizimida reactive programming uchun asosiy library.
Spring WebFlux, Spring Cloud Gateway, reactive Redis, reactive MongoDB ko‘pincha Reactor ustida ishlaydi.
Reactor’da ikkita asosiy type bor:
Mono<T>
Flux<T>8. Mono nima?
Mono - 0 yoki 1 ta qiymat qaytaradigan reactive type.
Mono<User> → user bo‘lishi mumkin yoki bo‘lmasligi mumkin
Mono<Void> → qiymat yo‘q, faqat operation tugashi muhimMisol:
Mono<User> userMono = userService.findById(1L);Bu darhol userni bermaydi. Bu kelajakda user kelishini ifodalovchi pipeline.
8.1. Mono oddiy misol
Mono.just("Hello")
.map(text -> text.toUpperCase())
.subscribe(System.out::println);Natija:
HELLOTushuntirish:
Mono.just("Hello") → bitta qiymat yaratadi
map(...) → qiymatni o‘zgartiradi
subscribe(...) → pipeline’ni ishga tushiradiMuhim:
Reactive pipeline
subscribebo‘lmaguncha ko‘pincha ishlamaydi.
Spring WebFlux controller’da esa siz odatda subscribe() chaqirmaysiz. Spring o‘zi subscribe qiladi.
9. Flux nima?
Flux - 0 dan N tagacha qiymat qaytaradigan reactive type.
Flux<User> → ko‘p user
Flux<Event> → eventlar oqimi
Flux<String> → stringlar oqimiMisol:
Flux.just("A", "B", "C")
.map(String::toLowerCase)
.subscribe(System.out::println);Natija:
a
b
c10. Mono vs Flux
Type | Nechta qiymat | Misol |
|---|---|---|
| 0 yoki 1 | user by id |
| 0 dan N gacha | users list, event stream |
Misollar:
Mono<User> findUserById(Long id);Flux<User> findAllUsers();Mono<Void> deleteUser(Long id);11. map va flatMap farqi
Reactive’da eng ko‘p chalkashadigan joylardan biri: map va flatMap.
map
map oddiy qiymatni boshqa qiymatga o‘zgartiradi.
Mono<User> userMono = userRepository.findById(id);
Mono<UserDto> dtoMono = userMono
.map(user -> new UserDto(user.getId(), user.getName()));Bu yerda:
User → UserDtoflatMap
flatMap ichida yana Mono yoki Flux qaytsa ishlatiladi.
Mono<Order> orderMono = userRepository.findById(userId)
.flatMap(user -> orderRepository.findLatestByUserId(user.getId()));Bu yerda:
User → Mono<Order>Agar map ishlatsangiz:
Mono<Mono<Order>>bo‘lib qoladi. Shuning uchun flatMap kerak.
12. Reactive chain misol
Traditional blocking:
public OrderDto getLatestOrder(Long userId) {
User user = userRepository.findById(userId);
Order order = orderRepository.findLatestByUserId(user.getId());
return mapper.toDto(order);
}Reactive:
public Mono<OrderDto> getLatestOrder(Long userId) {
return userRepository.findById(userId)
.flatMap(user -> orderRepository.findLatestByUserId(user.getId()))
.map(order -> mapper.toDto(order));
}Bu yerda thread DB javobini kutib turmaydi.
13. Spring WebFlux
Spring WebFlux - Spring’ning reactive web frameworki.
Spring MVC blocking modelda ishlaydi:
Servlet stack
Tomcat thread per requestSpring WebFlux reactive modelda ishlaydi:
Non-blocking stack
Event loop
Netty odatda defaultWebFlux ikki xil uslubni qo‘llaydi:
Annotation-based controller
Functional routing14. WebFlux Controller
@RestController
@RequiredArgsConstructor
@RequestMapping("/users")
public class UserController {
private final UserService userService;
@GetMapping("/{id}")
public Mono<UserDto> getUser(@PathVariable Long id) {
return userService.findById(id);
}
@GetMapping
public Flux<UserDto> getUsers() {
return userService.findAll();
}
}Bu yerda controller UserDto emas, Mono<UserDto> yoki Flux<UserDto> qaytaradi.
15. WebClient
Reactive HTTP client - WebClient.
RestTemplate blocking. WebClient reactive va non-blocking.
Misol:
@Service
@RequiredArgsConstructor
public class PaymentClient {
private final WebClient webClient;
public Mono<PaymentResponse> charge(PaymentRequest request) {
return webClient.post()
.uri("/payments")
.bodyValue(request)
.retrieve()
.bodyToMono(PaymentResponse.class);
}
}Config:
@Bean
WebClient paymentWebClient(WebClient.Builder builder) {
return builder
.baseUrl("https://payment-service")
.build();
}16. Parallel call misol
Reactive’da bir nechta tashqi servisni parallel chaqirish qulay.
Masalan checkout summary:
public Mono<CheckoutSummary> getSummary(Long userId) {
Mono<UserDto> userMono = userClient.getUser(userId);
Mono<CartDto> cartMono = cartClient.getCart(userId);
Mono<BonusDto> bonusMono = bonusClient.getBonus(userId);
return Mono.zip(userMono, cartMono, bonusMono)
.map(tuple -> new CheckoutSummary(
tuple.getT1(),
tuple.getT2(),
tuple.getT3()
));
}Bu uchta call ketma-ket emas, parallel bajarilishi mumkin.
Blocking modelda yomon variant:
UserDto user = userClient.getUser(userId);
CartDto cart = cartClient.getCart(userId);
BonusDto bonus = bonusClient.getBonus(userId);Agar har biri 300 ms bo‘lsa, umumiy 900 ms bo‘lishi mumkin. Reactive parallel chaqiriqda taxminan 300 ms atrofida tugashi mumkin.
17. Error handling
Reactive’da exceptionni try/catch bilan emas, operatorlar bilan boshqarasiz.
onErrorReturn
Xato bo‘lsa default qiymat qaytaradi.
return paymentClient.charge(request)
.onErrorReturn(new PaymentResponse("FAILED"));onErrorResume
Xato bo‘lsa boshqa pipeline’ga o‘tadi.
return paymentClient.charge(request)
.onErrorResume(ex -> {
log.warn("Payment failed, fallback used", ex);
return Mono.just(new PaymentResponse("PAYMENT_UNAVAILABLE"));
});doOnError
Faqat log yoki side effect uchun.
return paymentClient.charge(request)
.doOnError(ex -> log.error("Payment error", ex));Muhim:
doOnErrorxatoni yutmaydi. Faqat kuzatadi. Xato pipeline’da davom etadi.
18. Timeout
Reactive’da timeout juda muhim.
return paymentClient.charge(request)
.timeout(Duration.ofSeconds(2))
.onErrorResume(TimeoutException.class, ex ->
Mono.just(new PaymentResponse("TIMEOUT"))
);Agar timeout qo‘yilmasa, request uzoq osilib qolishi mumkin.
19. Retry
Retry ehtiyotkorlik bilan ishlatiladi.
return paymentClient.charge(request)
.retryWhen(
Retry.backoff(3, Duration.ofMillis(200))
.maxBackoff(Duration.ofSeconds(2))
);Lekin payment kabi non-idempotent operationlarda retry xavfli.
Yaxshi qoida:
Retry faqat idempotent yoki xavfsiz operationlarda.
Payment bo‘lsa idempotency key shart.20. Blocking call muammosi
Reactive app ichida blocking call qilish eng katta xatolardan biri.
Yomon:
public Mono<UserDto> getUser(Long id) {
User user = blockingJpaRepository.findById(id).orElseThrow();
return Mono.just(mapper.toDto(user));
}Bu WebFlux event loop threadini block qiladi.
Yana yomon:
return userReactiveRepository.findById(id)
.map(user -> {
Thread.sleep(1000);
return mapper.toDto(user);
});Event loopni block qilish butun app latency’sini buzadi.
21. Blocking kodni qanday ajratish mumkin?
Agar majburan blocking library ishlatish kerak bo‘lsa, uni alohida schedulerga o‘tkazish mumkin:
public Mono<UserDto> getUser(Long id) {
return Mono.fromCallable(() -> blockingJpaRepository.findById(id).orElseThrow())
.subscribeOn(Schedulers.boundedElastic())
.map(mapper::toDto);
}boundedElastic blocking I/O uchun mo‘ljallangan.
Lekin bu reactive’ning toza foydasini kamaytiradi. Agar app ko‘p joyda blocking bo‘lsa, WebFlux tanlash noto‘g‘ri bo‘lishi mumkin.
22. R2DBC
R2DBC - relational database bilan reactive non-blocking ishlash uchun API.
JDBC blocking. R2DBC reactive.
JDBC:
Thread DB javobini kutadiR2DBC:
Thread DB javobini kutib band bo‘lmaydiSpring Data R2DBC repository:
public interface UserRepository extends ReactiveCrudRepository<User, Long> {
Flux<User> findByStatus(String status);
}Service:
public Mono<UserDto> findById(Long id) {
return userRepository.findById(id)
.map(mapper::toDto);
}23. R2DBC cheklovlari
R2DBC har doim JPA/Hibernate o‘rnini to‘liq bosmaydi.
JPA/Hibernate’da bor:
Entity relationship
Lazy loading
First-level cache
Dirty checking
JPQL
Criteria APIR2DBC’da bular ancha cheklangan.
R2DBC ko‘proq:
simple query
high concurrency I/O
reactive pipeline
manual mappinguchun mos.
Murakkab domain model va ORM qulayliklari kerak bo‘lsa, JPA hali ham kuchli.
24. Reactive transaction
Reactive transaction ham bor, lekin blocking transactiondan farq qiladi.
@Transactional
public Mono<Order> createOrder(CreateOrderRequest request) {
return orderRepository.save(new Order(request))
.flatMap(order -> outboxRepository.save(toEvent(order)).thenReturn(order));
}Spring reactive transaction contextni thread-local orqali emas, Reactor context orqali olib yuradi.
Shuning uchun oddiy blocking mental model har doim ishlamaydi.
25. Reactor Context
Reactive’da bitta request har xil threadlarda davom etishi mumkin. Shuning uchun ThreadLocal har doim ishonchli emas.
Reactor’da Context bor.
Misol:
return Mono.deferContextual(ctx -> {
String correlationId = ctx.get("correlationId");
return Mono.just("correlationId=" + correlationId);
});Context yozish:
return service.call()
.contextWrite(ctx -> ctx.put("correlationId", "abc-123"));Security, tracing, transaction kabi narsalarda context muhim.
26. ThreadLocal va MDC muammosi
Traditional Spring MVC’da MDC ko‘pincha thread-localga tayanadi.
Reactive’da request bir threaddan boshqasiga o‘tishi mumkin:
request start: thread-1
db response: thread-3
http response: thread-5Shuning uchun MDC/correlation ID ni reactive context bilan to‘g‘ri integratsiya qilish kerak.
OpenTelemetry va zamonaviy Spring stack bu masalada ancha yordam beradi.
27. Schedulers
Reactor’da scheduler - ish qaysi thread poolda bajarilishini belgilaydi.
Ko‘p ishlatiladiganlar:
Scheduler | Qachon |
|---|---|
| CPU-bound qisqa ishlar |
| Blocking I/O |
| Bitta thread kerak bo‘lsa |
| Hozirgi thread |
Misol:
return Mono.fromCallable(() -> heavyCalculation())
.subscribeOn(Schedulers.parallel());Blocking call:
return Mono.fromCallable(() -> blockingFileRead())
.subscribeOn(Schedulers.boundedElastic());28. publishOn vs subscribeOn
Bu senior darajada bilish kerak bo‘lgan mavzu.
subscribeOn
Pipeline boshlanishi qaysi scheduler’da bo‘lishini belgilaydi.
Mono.fromCallable(() -> blockingCall())
.subscribeOn(Schedulers.boundedElastic());publishOn
Undan keyingi operatorlar qaysi scheduler’da bajarilishini belgilaydi.
return userRepository.findById(id)
.publishOn(Schedulers.parallel())
.map(this::heavyMapping);Oddiy qoida:
subscribeOn → source qayerda ishlaydi
publishOn → keyingi operatorlar qayerda ishlaydi29. Hot vs Cold Publisher
Cold publisher
Har bir subscriber uchun ish qaytadan boshlanadi.
Flux<Integer> numbers = Flux.range(1, 3);
numbers.subscribe(System.out::println);
numbers.subscribe(System.out::println);Har subscriber 1,2,3 ni alohida oladi.
Hot publisher
Data subscriber bor-yo‘qligidan qat’i nazar chiqaveradi.
Misol:
live stock price
chat messages
sensor events
Kafka streamAgar subscriber kech ulansa, oldingi eventlarni o‘tkazib yuborishi mumkin.
30. WebFlux streaming
WebFlux streaming response qaytara oladi.
@GetMapping(value = "/events", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
public Flux<ServerSentEvent<String>> events() {
return Flux.interval(Duration.ofSeconds(1))
.map(i -> ServerSentEvent.builder("event-" + i).build());
}Bu har sekundda event yuboradi.
Mos joylar:
live notification;
monitoring dashboard;
real-time status;
chat;
progress update.
31. Functional routing
WebFlux’da controller o‘rniga functional endpoint ishlatish mumkin.
@Configuration
public class UserRoutes {
@Bean
RouterFunction<ServerResponse> routes(UserHandler handler) {
return RouterFunctions.route()
.GET("/users/{id}", handler::getUser)
.GET("/users", handler::getUsers)
.build();
}
}Handler:
@Component
@RequiredArgsConstructor
public class UserHandler {
private final UserService userService;
public Mono<ServerResponse> getUser(ServerRequest request) {
Long id = Long.valueOf(request.pathVariable("id"));
return userService.findById(id)
.flatMap(user -> ServerResponse.ok().bodyValue(user))
.switchIfEmpty(ServerResponse.notFound().build());
}
public Mono<ServerResponse> getUsers(ServerRequest request) {
return ServerResponse.ok().body(userService.findAll(), UserDto.class);
}
}Bu uslub kamroq ishlatiladi, lekin gateway/highly functional style yoqtiradiganlarda uchraydi.
32. Testing: StepVerifier
Reactive pipeline’ni test qilish uchun StepVerifier ishlatiladi.
@Test
void shouldReturnUppercase() {
Mono<String> result = Mono.just("hello")
.map(String::toUpperCase);
StepVerifier.create(result)
.expectNext("HELLO")
.verifyComplete();
}Error test:
@Test
void shouldReturnError() {
Mono<String> result = Mono.error(new IllegalArgumentException("bad"));
StepVerifier.create(result)
.expectError(IllegalArgumentException.class)
.verify();
}33. WebTestClient
WebFlux endpoint test qilish uchun:
@WebFluxTest(UserController.class)
class UserControllerTest {
@Autowired
private WebTestClient webTestClient;
@Test
void shouldReturnUser() {
webTestClient.get()
.uri("/users/1")
.exchange()
.expectStatus().isOk()
.expectBody()
.jsonPath("$.id").isEqualTo(1);
}
}WebTestClient Spring MVC testlarida ham ishlatilishi mumkin, lekin WebFlux’da juda tabiiy.
34. Reactive va database pool
Reactive app’da ham DB resurs cheksiz emas.
Agar R2DBC pool kichik bo‘lsa:
Request ko‘p
DB connection kam
Pending request oshadi
Latency oshadiShuning uchun monitoring kerak:
R2DBC pool usage
pending acquire
query latency
timeoutReactive thread kam ishlatadi, lekin DB connection, CPU, network baribir cheklangan.
35. Reactive performance xatolari
Xato 1: Event loopni block qilish
Thread.sleep(1000)
blockingRepository.findById()
file.readAllBytes()
RestTemplate callBular WebFlux event loopda ishlasa, tizim sekinlashadi.
Xato 2: .block() ishlatish
Yomon:
User user = userRepository.findById(id).block();Agar reactive pipeline ichida .block() ishlatilsa, non-blocking model buziladi.
Controller’da ayniqsa yomon:
@GetMapping("/{id}")
public UserDto getUser(@PathVariable Long id) {
return userService.findById(id).block();
}To‘g‘ri:
@GetMapping("/{id}")
public Mono<UserDto> getUser(@PathVariable Long id) {
return userService.findById(id);
}Xato 3: Reactive + JPA aralashtirish
WebFlux controller, lekin ichida JPA blocking repository:
return Mono.just(jpaRepository.findById(id));Bu reactive emas. Bu blocking kodni Mono ichiga o‘rash xolos.
Xato 4: Business logicni haddan tashqari chain qilish
Reactive kod o‘qilishi qiyinlashishi mumkin.
Yomon:
return a.flatMap(x -> b(x).flatMap(y -> c(y).flatMap(z -> d(z))));Yaxshiroq:
methodlarga bo‘lish;
nomlangan private methodlar ishlatish;
pipeline’ni o‘qiladigan qilish.
Xato 5: Error handling yo‘q
Reactive’da exception pipeline ichida oqadi. Har doim timeout, retry, fallback strategiyasi bo‘lishi kerak.
36. Virtual threads vs Reactive
Java 21 bilan virtual threads production darajada kuchli variant bo‘ldi.
Virtual thread bilan blocking kod yozasiz, lekin har request uchun arzon virtual thread ishlaydi.
Spring MVC + virtual threads:
spring:
threads:
virtual:
enabled: trueKod oddiy blocking ko‘rinishda qoladi:
@GetMapping("/{id}")
public UserDto getUser(@PathVariable Long id) {
User user = userRepository.findById(id).orElseThrow();
return mapper.toDto(user);
}Lekin thread resursi platform threaddan ancha arzon.
36.1. Reactive afzalligi
Reactive yaxshi:
Streaming
Backpressure
High concurrency non-blocking I/O
Gateway
WebSocket
Event stream
End-to-end reactive stack36.2. Virtual thread afzalligi
Virtual thread yaxshi:
Oddiy blocking kod
Debugging osonroq
JPA/JDBC bilan mos
Teamga tushunarli
Migration osonroq36.3. Qaysi birini tanlash kerak?
Holat | Yaxshi tanlov |
|---|---|
Oddiy CRUD + JDBC/JPA | Spring MVC + virtual threads |
Ko‘p tashqi HTTP call | WebFlux yoki virtual threads |
Streaming/backpressure kerak | WebFlux/Reactor |
WebSocket/live events | WebFlux |
Team reactive bilmaydi | Virtual threads |
End-to-end reactive DB/client bor | WebFlux |
Legacy blocking library ko‘p | Virtual threads |
Muhim xulosa:
Virtual threads reactive’ni butunlay yo‘q qilmaydi. Lekin oddiy backend CRUD va blocking I/O uchun reactive’ga ehtiyojni kamaytiradi.
37. Real production tanlov misollari
Ecommerce order service
Spring MVC + JPA + virtual threadsKo‘pincha yetarli. Chunki business logic va transactionlar oddiyroq.
API Gateway
Spring Cloud Gateway / WebFluxChunki ko‘p concurrent connection va non-blocking proxy muhim.
Notification streaming
WebFlux + Server-Sent Events yoki WebSocketChunki clientlarga real-time event kerak.
Analytics event processing
Kafka Streams / Reactor / async pipelineChunki oqim bilan ishlash kerak.
38. Reactive observability
Reactive app’da observability yanada muhim.
Kuzatish kerak:
event loop blocked time
request latency
operator error rate
WebClient latency
R2DBC query latency
connection pool pending
retry count
timeout count
backpressure/drop countLog va tracingda context propagation muhim, chunki bitta request bir nechta threadlarda davom etishi mumkin.
39. Reactive security
Spring Security WebFlux’da ham bor, lekin classlar farq qiladi.
MVC:
SecurityFilterChainWebFlux:
SecurityWebFilterChainMisol:
@Configuration
@EnableWebFluxSecurity
public class SecurityConfig {
@Bean
SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http) {
return http
.csrf(ServerHttpSecurity.CsrfSpec::disable)
.authorizeExchange(exchange -> exchange
.pathMatchers("/public/**").permitAll()
.pathMatchers("/admin/**").hasRole("ADMIN")
.anyExchange().authenticated()
)
.oauth2ResourceServer(oauth2 -> oauth2.jwt(Customizer.withDefaults()))
.build();
}
}Reactive security context ham thread-localga emas, reactive contextga bog‘liq.
40. Senior checklist
Reactive ishlatishdan oldin tekshir:
Haqiqatan non-blocking kerakmi?
Team Reactor/WebFlux’ni tushunadimi?
DB layer R2DBCmi yoki blocking JPAmi?
Tashqi clientlar WebClientmi?
Pipeline ichida .block() yo‘qmi?
Thread.sleep yoki blocking call yo‘qmi?
Timeout/retry/fallback bor-mi?
Backpressure kerakmi?
Observability sozlanganmi?
MDC/context propagation to‘g‘rimi?
Virtual threads oddiyroq yechim bo‘la oladimi?41. Interview savollari
Asosiy tushunchalar
Reactive programming nima?
Blocking va non-blocking farqi nima?
Reactive Streams spec nima?
Backpressure nima?
Mono va Flux farqi nima?
Reactor
mapvaflatMapfarqi?subscribeOnvapublishOnfarqi?Hot va cold publisher nima?
doOnError,onErrorResume,onErrorReturnfarqi?.block()nima uchun xavfli?
Spring WebFlux
Spring MVC va WebFlux farqi?
WebClient va RestTemplate farqi?
WebFlux ichida JPA ishlatish xavflimi?
R2DBC nima?
WebFlux security MVC securitydan nimasi bilan farq qiladi?
Architecture
Reactive qachon kerak?
Virtual threads reactive o‘rnini bosadimi?
Gateway uchun qaysi model yaxshi?
Oddiy CRUD uchun reactive kerakmi?
Reactive debugging qiyinchiliklari nima?
42. Amaliy topshiriqlar
Topshiriq 1: Mono va Flux
Quyidagilarni yozing:
Mono<String> → uppercase
Flux<Integer> → faqat juft sonlar
Flux<User> → UserDto ga mapTopshiriq 2: WebFlux CRUD
Endpointlar:
GET /users/{id} → Mono<UserDto>
GET /users → Flux<UserDto>
POST /users → Mono<UserDto>Repository sifatida vaqtincha in-memory map yoki reactive repository ishlating.
Topshiriq 3: WebClient
user-service, cart-service, bonus-service ni parallel chaqirib:
GET /checkout-summary/{userId}qaytaring.
Talab:
Mono.zip ishlatilsin
Har clientda timeout bo‘lsin
Fallback bo‘lsinTopshiriq 4: Blocking xatoni topish
WebFlux app ichida ataylab:
Thread.sleep(1000);qo‘ying.
Keyin load test qilib latency qanday buzilishini kuzating. So‘ng uni:
Mono.delay(...)yoki boundedElastic bilan almashtiring.
Topshiriq 5: StepVerifier
Service methodlarni test qiling:
success case
empty case
error case
timeout case43. Qisqa xulosa
Reactive programming Senior Java developer uchun kuchli, lekin ehtiyotkorlik bilan ishlatiladigan skill.
Asosiy fikrlar:
Reactive - async data oqimi bilan ishlash
Mono - 0 yoki 1 qiymat
Flux - 0 dan N gacha qiymat
WebFlux - Spring reactive web framework
WebClient - non-blocking HTTP client
R2DBC - reactive relational DB access
Backpressure - consumer ulguradigan tezlikda data olish
.block() - reactive pipeline ichida xavfli
Virtual threads - oddiy blocking kod uchun kuchli alternativEng muhim qoida:
Reactive programming’ni "zamonaviy" bo‘lgani uchun emas, aniq muammo uchun tanlang: high concurrency, non-blocking I/O, streaming yoki backpressure kerak bo‘lsa. Oddiy CRUD backendda virtual threads ko‘pincha soddaroq va arzonroq yechim bo‘ladi.