티스토리 뷰
각각의 스레드에서 상태 값을 저장하여 사용할 수 있는 스레드로컬과 유사하게 리액터에서는 컨텍스트를 사용해서 리액터 시퀀스상에 상태 값을 저장하고, 저장된 상태 값을 사용할 수 있다.
먼저 리액터에서의 컨텍스트가 무엇인지 살펴보고, 컨텍스트의 특징과 자주 사용되는 API를 살펴보자
컨텍스트란
Reactor Sequence
상에서 상태를 저장할 수 있고, 저장된 상태 값을Operator
체인에서 공유해서 사용할 수 있는 인터페이스이다.Context
에 값을 저장하기 위해서는contextWrite()
를 사용하고, 저장된 상태 값은 key, value 형태로 저장된다.Context
에 저장된 값을 읽어오기 위해서는 읽기 전용 뷰인ContextView
를 사용한다.ContextView
는Reactor Sequence
에서deferContextual()
또는transformDeferredContextual()
을 통해서 제공된다.
예제코드
public class ContextIntroduceExample01 {
public static void main(String[] args) throws InterruptedException {
String key = "message";
Mono<String> mono = Mono.deferContextual(ctx ->
Mono.just("Hello" + " " + ctx.get(key)).doOnNext(Logger::doOnNext)
)
.subscribeOn(Schedulers.boundedElastic())
.publishOn(Schedulers.parallel())
.transformDeferredContextual((mono2, ctx) -> mono2.map(data -> data + " " + ctx.get(key)))
.contextWrite(context -> context.put(key, "Reactor"));
mono.subscribe(data -> Logger.onNext(data));
Thread.sleep(100L);
}
}
- 실행 결과를 보면
Mono.deferContextual
에서contextWrite(context -> context.put(key, "Reactor"))
를 통해 저장된 값을 한번 읽어오고,transformDeferredContextual((mono2, ctx) -> mono2.map(data -> data + " " + ctx.get(key)))
에서 key에 저장된 값을 한번 더 추가하기 때문에Hello Reactor Reactor
결과가 출력된 것을 확인할 수 있다. - 두 쓰레드가 서로 다르지만, 리액터에서의
context
를 이용하면context
내부에 저장된 상태 값을 공유하기 때문에 위와 같은 결과가 나올 수 있었다.
자주 사용되는 Context API
리액터에서 사용할 수 있는 Context API
는 크게 두 가지로 나뉘는데, Context
에 대한 API와 ContextView
에 대한 API로 분류할 수 있다.
Context에 대한 API (쓰기)
- put(key, value): key/value 형태로 Context에 값을 쓴다.
- ContextOf(key1, value1, key2, value2, ...): key/value 형태로 Context에 여러 개의 값을 쓴다.
- putAll(ContextView): 파라미터로 입력된 ContextView를 merge한다.
- delete(key): Context에서 key에 해당하는 value를 삭제한다.
ContextView API (읽기)
- get(key): ContextView에서 key에 해당하는 value를 반환한다.
- getOrEmpty(key): ContextView에서 key에 해당하는 value를 Optional로 래핑해서 반환한다.
- getOrDefault(key, default value): ContextView에서 key에 해당하는 value를 가져온다. 만약 key에 해당하는 value가 없으면 dafault value를 가져온다.
- hasKey(key): ContextView에서 특정 key가 존재하는지 확인한다.
- isEmpty(): Context가 비어있는지 확인한다.
- size(): Context내에 있는 key/value의 개수를 반환한다.
Context의 특징
리액터 시퀀스에서 사용하는 컨텍스트는 몇가지 알아두어야할 특징이 있다.
- Context는 각각의 subscriber를 통해 Reactor Sequence에 연결되며, 체인에서 각각의 Operator들이 실행 쓰레드가 달라도 연결된 Context에 접근할 수 있다.
- Context는 체인의 맨 아래에서부터 위로 전파된다.
- Context는 Downstream에서 Upstream으로 전파된다.
- Operator 체인에서 Context read 메서드가 Context write 메서드 밑에 있을 경우에는 write된 값을 read할 수 없다.
- 따라서 일반적으로 Context에 write 할때에는 Operator 체인의 마지막에 둔다.
- 동일한 키에 대해서 write할 경우, 값을 덮어쓴다.
- 메인 Operator 내부에서 Sequence를 생성하는 flatMap()같은 Operator내에서 write된 Context의 값은 Inner Sequence 내부에서만 유효하고, 외부 Operator 체인에서는 보이지 않는다. (즉, Inner Sequence에서 저장된 데이터는 Inner Sequence에서만 사용할 수 있다.)
예제코드
public class ContextFetureExample01 {
public static void main(String[] args) throws InterruptedException {
String key1 = "name";
Mono<String> mono = Mono.deferContextual(ctx ->
Mono.just("name: " + ctx.get(key1))
)
.publishOn(Schedulers.parallel());
mono.contextWrite(context -> context.put(key1, "hyuuny"))
.subscribe(data -> Logger.onNext("subscriber 1", data));
mono.contextWrite(context -> context.put(key1, "world"))
.subscribe(data -> Logger.onNext("subscriber 2", data));
Thread.sleep(100L);
}
- 실행 결과를 보면 첫 번째 구독에서는 hyuuny라는 값이 출력되었고, 두 번째 구독에서는 world라는 값이 출력되었다. 즉, 컨텍스트는 구독이 발생할 때마다 하나씩 연결이 된다는 사실을 알 수 있다.
public class ContextFetureExample02 {
public static void main(String[] args) throws InterruptedException {
String key1 = "name";
Mono.deferContextual(ctx ->
Mono.just("name: " + ctx.get(key1))
)
.publishOn(Schedulers.parallel())
.contextWrite(context -> context.put(key1, "hyuuny"))
.contextWrite(context -> context.put(key1, "world"))
.subscribe(Logger::onNext);
Thread.sleep(100L);
}
}
- Context는 Downstream -> Upstream으로 전파되기 때문에, 아래쪽에 위치한 world가 위에서 저장한 hyuuny라는 값으로 덮어씌워진 것을 확인할 수 있다.
'Spring' 카테고리의 다른 글
[Spring Webflux] Functional Endpoints (0) | 2024.05.07 |
---|---|
[Spring Webflux] DispatcherHandler (0) | 2024.05.06 |
[Spring Webflux] 스케줄러 (Scheduler) (0) | 2024.01.21 |
[Spring Webflux] 백프레셔 (Backpressure) (2) | 2024.01.15 |
[Spring Webflux] Cold Sequence & Hot Sequence (0) | 2024.01.07 |
댓글
공지사항
최근에 올라온 글
최근에 달린 댓글
- Total
- Today
- Yesterday
링크
TAG
- webflux
- leetcode
- 자료구조
- 백준
- Spring
- 스프링 부트
- 릿코드
- spring boot
- mysql 8.0
- 코테
- Algorithm
- 노마드코더
- 문자열
- 알고리즘
- 북클럽
- 김영한
- 스프링부트
- 데이터베이스
- 스프링
- 리팩토링
- 정렬
- 코틀린
- kotlin
- MySQL
- 인프런
- 그리디
- 파이썬
- Real MySQL
- 구현
- 노마드
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | |||
5 | 6 | 7 | 8 | 9 | 10 | 11 |
12 | 13 | 14 | 15 | 16 | 17 | 18 |
19 | 20 | 21 | 22 | 23 | 24 | 25 |
26 | 27 | 28 | 29 | 30 | 31 |
글 보관함