Reactive Programming
โณ๏ธ ์ ํต์ ์ธ ์ฝ๋ฐฑ ๊ธฐ๋ฐ API๋ Future์ ๊ฐ์ JDK์ ๋น๋๊ธฐ ์ฝ๋ ์์ฑ ๋ฐฉ์์ ๋นํด ๋ ์ ์ฐํ๊ณ ํจ์จ์
1. ๋น๋๊ธฐ ์ฒ๋ฆฌ์ ๊ฐ์ํ : ๋น๋๊ธฐ ์์ ์ ์คํธ๋ฆผ์ ํํ๋ก ์ฒ๋ฆฌํ๋ฏ๋ก ๋ฐ์ดํฐ์ ํ๋ฆ์ ํตํด ๊ฐ ๋จ๊ณ๋ฅผ ์ฐ๊ฒฐํ๊ณ ๋ฐ์ดํฐ๊ฐ ์ค๋น๋๋ ์ฆ์ ์ฒ๋ฆฌ ๊ฐ๋ฅ
2. ์ ์ธ์ API ์ ๊ณต : Reactor, RxJava์ ๊ฐ์ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ map, filter, reduce์ ๊ฐ์ ํจ์ํ ํ๋ก๊ทธ๋๋ฐ ์คํ์ผ์ ์ฐ์ฐ์๋ฅผ ์ ๊ณตํ์ฌ ๋ฐ์ดํฐ ๋ณํํ๊ณ ์กฐ์ํ๋ ๊ณผ์ ์ ๊ฐ๊ฒฐํ๊ฒ ํํ
3. backPressure ์ง์ : ๋ฐ์ดํฐ ์๋น์๊ฐ ๋ฐ์ดํฐ ์์ฐ์์ ์๋๋ฅผ ์ ์ดํ ์ ์๋๋ก ํจ
4. ๋ณต์ก์ฑ ๊ฐ์์ ๊ฐ๋ ์ฑ ํฅ์ : ์ฐ์ฐ์ ์ฒด์ด๋์ ํตํด ์ฝ๋์ ๊ฐ๋ ์ฑ ๋์ด๊ณ ๊ฐ ๋จ๊ณ์ ์์ ์ ๋ถ๋ฆฌํ์ฌ ๊ฐ๋ฐ์๊ฐ ์ฝ๋๋ฅผ ์ดํดํ๊ณ ์ ์ง๋ณด์ํ๊ธฐ ์ฝ๊ฒ ํจ
- stream (์คํธ๋ฆผ)
- ๋ฐ์ดํฐ์ ์ฐ์์ ์ธ ํ๋ฆ
- event-driven (์ด๋ฒคํธ ๊ธฐ๋ฐ)
- ์ธ๋ถ ํ๊ฒฝ์ด๋ ์ฌ์ฉ์ ์ ๋ ฅ๊ณผ ๊ฐ์ ์ด๋ฒคํธ์ ๋ฐ์ํ์ฌ ๋์
- ์ด๋ฒคํธ๊ฐ ๋ฐ์ํ ๋๋ง๋ค ๊ทธ์ ๋ฐ๋ผ ๋น๋๊ธฐ์ ์ผ๋ก ์ฒ๋ฆฌ
- Async (๋น๋๊ธฐ์ฑ)
- ์ฌ๋ฌ ์์ ์ด ๋์์ ์คํ๋ ์ ์์ผ๋ฉฐ ๊ฒฐ๊ณผ๋ ์์ ์ด ์๋ฃ๋ ๋๊น์ง ๊ธฐ๋ค๋ฆฌ์ง ์๊ณ ์ด๋ฒคํธ๋ ์ฝ๋ฐฑ์ ํตํด ์ฒ๋ฆฌ๋จ
โณ๏ธ ์๋ฐ์์ ์ ๊ณตํ๋ ๋น๋๊ธฐ ํ๋ก๊ทธ๋๋ฐ vs Reactor ์ฝ๋
userService.getFavorites(userId, new Callback<List<String>>() {
public void onSuccess(List<String> list) {
if (list.isEmpty()) {
suggestionService.getSuggestions(new Callback<List<Favorite>>() {
public void onSuccess(List<Favorite> list) {
UiUtils.submitOnUiThread(() -> {
list.stream()
.limit(5)
.forEach(uiList::show);
});
}
public void onError(Throwable error) {
UiUtils.errorPopup(error);
}
});
} else {
list.stream()
.limit(5)
.forEach(favId -> favoriteService.getDetails(favId,
new Callback<Favorite>() {
public void onSuccess(Favorite details) {
UiUtils.submitOnUiThread(() -> uiList.show(details));
}
public void onError(Throwable error) {
UiUtils.errorPopup(error);
}
}
));
}
}
public void onError(Throwable error) {
UiUtils.errorPopup(error);
}
});
์์ฝํ๋ฉด ๋ค์๊ณผ ๊ฐ๋ค
1. ๋น๋๊ธฐ ์์ ์ ์ฌ๋ฌ ๋จ๊ณ๋ก ์ํํ๋ฉด์, ์ฌ์ฉ์์ ์ฆ๊ฒจ์ฐพ๊ธฐ ๋ชฉ๋ก์ ๋จผ์ ๊ฐ์ ธ์ค๊ณ , ์ฆ๊ฒจ์ฐพ๊ธฐ๊ฐ ์๋ ๊ฒฝ์ฐ ์ถ์ฒ ํญ๋ชฉ์ ์ ๊ณตํ๋ ๊ตฌ์กฐ
2. ๊ฐ ๋จ๊ณ์์ ์ฑ๊ณต๊ณผ ์ค๋ฅ ์ฒ๋ฆฌ๋ฅผ ์ํ ์ฝ๋ฐฑ ์ ๊ณต
๐ ์ฝ๋ฐฑ ์ง์ฅ์ ๋น ์ง ์ ์๋ค
์ค์ฒฉ๋ ์ฝ๋ฐฑ ํจ์๋ค์ด ์ฌ๋ฌ ๋จ๊ณ๋ก ๊ตฌ์ฑ๋์ด ์๊ณ , ์ฝ๋๊ฐ ์ ์ ๊น์ด์ง๋ฉด์ ๊ฐ๋ ์ฑ ๋ํ ๋จ์ด์ง๊ณ ์ ์ง๋ณด์๊ฐ ์ด๋ ค์์ง๋ค.
userService.getFavorites(userId)
.flatMap(favoriteService::getDetails)
.switchIfEmpty(suggestionService.getSuggestions())
.take(5)
.publishOn(UiUtils.uiThreadScheduler())
.subscribe(uiList::show, UiUtils::errorPopup);
Reactor ์ฝ๋๋ก ๋ํ๋ด๋ฉด ์์ ๊ฐ๋ค.
1. flatMap : ์ฌ๋ฌ ์ฆ๊ฒจ์ฐพ๊ธฐ ID์ ๋ํ ์์ฒญ์ ์ฒ๋ฆฌํ๊ณ ๊ทธ ๊ฒฐ๊ณผ๋ฅผ ํ๋์ ์คํธ๋ฆผ์ผ๋ก ๋ฐํ
2. switchIfEmpty : ์คํธ๋ฆผ์ด ๋น์ด์์ ๊ฒฝ์ฐ, ์ฆ ์ฆ๊ฒจ์ฐพ๊ธฐ ๋ชฉ๋ก์ด ๋น์ด์์ ๊ฒฝ์ฐ ํธ์ถ๋๋ ๋ฉ์๋
3. take(5) : ์คํธ๋ฆผ์์ ์ต๋ 5๊ฐ์ ํญ๋ชฉ๋ง ๊ฐ์ ธ์ค๋๋ก ์ ํ
4. publishOn : ๋ค์ ๋จ๊ณ์ ์คํ์ UI ์ค๋ ๋์์ ์ํํ๋๋ก ์ง์ (ํน์ ์ค์ผ์ค๋ฌ์์ ์คํํ๋๋ก ์ง์ )
5. subscribe : ์คํธ๋ฆผ ๊ตฌ๋
Reactive Streams
๋น๋๊ธฐ์ ์ด๊ณ ๋ฐ์ดํฐ๋ฅผ ํจ์จ์ ์ผ๋ก ์ฒ๋ฆฌํ ์ ์๋ ์คํธ๋ฆผ ์ฒ๋ฆฌ๋ฅผ ์ํ ํ์ค ์ ์
- Publisher
- ๋ฐ์ดํฐ ์คํธ๋ฆผ์ ์์ฑํ๊ณ ๋ฐ์ดํฐ๋ฅผ ๋ฐํํ๋ ์ญํ
- onSubscribe, onNext, onError, onComplete ๋ฉ์๋๋ฅผ ํตํด ๋ฐ์ดํฐ ์ ์ก
- onSubscribe : subscription ๊ฐ์ฒด ์ ๋ฌ
- onNext : subscriber๋ ๋ฐ์ดํฐ๋ฅผ ๋ฐ๊ณ ์ฒ๋ฆฌ
- onComplete : ๋ชจ๋ ์์ดํ ์ด ์ ๋ฌ ์๋ฃ๋์ด ๋ ์ด์ ์ ๋ฌํ ๋ฐ์ดํฐ๊ฐ ์์ ๋ ํธ์ถ -> publisher์ subscriber ์ฐ๊ฒฐ ์ข ๋ฃ
- onError : ๋ฐ์ดํฐ ์คํธ๋ฆผ ์ฒ๋ฆฌ ์ค ์ค๋ฅ ๋ฐ์์ ํธ์ถ
- subscribe ํจ์ ์ ๊ณตํด์ publisher์ ๋ค์์ subscriber ๋ฑ๋ก ์ง์
- ColdPublisher
- subscriber๊ฐ ๊ตฌ๋ ํ ๋๋ง๋ค ์๋ก์ด ๋ฐ์ดํฐ ์คํธ๋ฆผ ์์ฑ
- HotPublisher
- ๋ฐ์ดํฐ ์คํธ๋ฆผ์ด ๊ตฌ๋ ์์๊ฒ ๋ ๋ฆฝ์ ์ผ๋ก ์์ฑ๋์ง ์๊ณ , ์คํธ๋ฆผ์ด ์ด๋ฏธ ํ์ฑํ๋์ด ์๋ ์ํ์์ subscriber๊ฐ ์คํธ๋ฆผ์ ์ ๊ทผํจ
- ๋ชจ๋ subscriber๊ฐ ์คํธ๋ฆผ ๊ณต์ ํ๋ฉฐ ํ์ฌ ์ํ๋ ์ค๊ฐ ๊ฒฐ๊ณผ๋ฅผ ๋ฐ์
- Subscriber
- ๋ฐ์ดํฐ ์คํธ๋ฆผ์ ์๋นํ๊ณ ์ฒ๋ฆฌํ๋ ์ญํ
- subscribeํ๋ ์์ ์ publisher๋ก๋ถํฐ subscription์ ๋ฐ์ ์ ์๋ ์ธ์ ์ ๊ณต
- Subscription
- Publisher์ Subscriber ๊ฐ์ ์ฐ๊ฒฐ
- ๋ฐ์ดํฐ ํ๋ฆ ์ ์ด
โณ๏ธ ๊ตฌํ ๋ผ์ด๋ธ๋ฌ๋ฆฌ
- Project reactor
- Mono์ Flux publisher ์ ๊ณต
- Flux : 0๊ฐ ์ด์์ ์์๋ฅผ ๋น๋๊ธฐ์ ์ผ๋ก ์ฒ๋ฆฌํ๋ ๋ฐ์ดํฐ ์คํธ๋ฆผ ๐ ๋ค์์ ์์ ์ฒ๋ฆฌ โ List<T>
- Mono : ์ต๋ 1๊ฐ์ ์์๋ฅผ ๋น๋๊ธฐ์ ์ผ๋ก ์ฒ๋ฆฌํ๋ ๋ฐ์ดํฐ ์คํธ๋ฆผ ๐ ๋จ์ผ ๊ฐ์ด๋ ๋น ๊ฐ ์ฒ๋ฆฌ โ Optional<T>
- subscribeOn() : ๋ค๋ฅธ ์ค๋ ๋์์ ์คํธ๋ฆผ์ด ์ฒ๋ฆฌ๋๋๋ก ํจ
๐จFlux์์ ํ๋์ ๊ฐ๋ง ๋๊ฒจ์ฃผ๋ฉด ๋๋๋ฐ Mono๋ฅผ ์ฌ์ฉํ๋ ์ด์ ..?
1. ๋ช ํํ ์๋ ํํ = ๋ฐํ๋๋ ๊ฐ์ด ๋จ์ผ ํญ๋ชฉ์
2. Mono<Void>๋ก ํน์ ์ฌ๊ฑด์ด ์๋ฃ๋๋ ์์ ์ ๊ฐ๋ฆฌํฌ ์ ์์
3. onNext ์ดํ ๋ฐ๋ก onComplete๋ฅผ ํธ์ถํ๋ฉด ๋๊ธฐ ๋๋ฌธ์ ๊ตฌํ์ด ๋ ๊ฐ๋จ
- RxJava
Reactor
1. Reactive Streams๋ฅผ ๊ตฌํํ ๋น๋๊ธฐ ๋ฐ์ดํฐ ์คํธ๋ฆผ ์ฒ๋ฆฌ ์ง์
2. Spring WebFlux์์ ๋ฉ์ธ์ผ๋ก ์ฌ์ฉ
3. backpressure๋ฅผ ์ ๊ณตํ์ฌ ์์ ์ฑ ๋์
4. ๋ค์ํ ์ฐ์ฐ์๋ก ๋ค์ํ ์ฐ์ฐ๋ค์ ์กฐํฉํ์ฌ ๊ฐ๋ ์ฑ ์ฆ๋
- subscribe : subscribe๋ฅผ ํ์ง ์์ผ๋ฉด ์๋ฌด์ผ๋ ์๊ธฐ์ง X
์ฐธ๊ณ ์๋ฃ
https://d2.naver.com/helloworld/2771091
https://techblog.woowahan.com/12903/
https://tech.io/playgrounds/929/reactive-programming-with-reactor-3/Intro
https://projectreactor.io/docs/core/release/reference/#getting-started-introducing-reactor
'Spring > Spring WebFlux' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
[๐ Reactive] 1. Reactive ์์คํ ๊ณผ Reactive ํ๋ก๊ทธ๋๋ฐ (0) | 2024.12.16 |
---|---|
[WebFlux] Reactor ์ฐ์ฐ์ ์ ๋ฆฌ (0) | 2024.07.17 |
[WebFlux] flatMap๊ณผ map์ ์ฐจ์ด (0) | 2024.07.17 |
[WebFlux] ๋น๋๊ธฐ/๋๊ธฐ, non-blocking/blocking, CompletableFuture (0) | 2024.07.03 |
[WebFlux] Spring WebFlux๋? (0) | 2024.01.13 |