1. Context 소개
- Context는 Project Reactor에서 제공하는 리액티브 스트림의 메타데이터 저장소입니다.
- 키/값 형태의 데이터를 저장하고 전파하는 역할을 수행합니다.
- ThreadLocal과 유사하지만 리액티브 스트림에 최적화된 방식으로 동작합니다.
- ThreadLocal은 스레드별로 데이터를 저장하고 전파하는 반면, Context는 리액티브 스트림의 구독자별로 데이터를 저장하고 전파합니다.
- 즉 구동이 발생할 때마다 해당 구독과 연결된 하나의 Context가 생성된다고 볼 수 있습니다.
- 구독자로부터 발행자 방향으로(downstream에서 upstream으로) 전파되는 특성을 가집니다.
- 주로 인증 정보, 추적 ID, 로깅 설정 등의 메타데이터를 전달하는 데 사용됩니다.
2. Context의 주요 특징
2.1 불변성(Immutability)
- Context는 불변(immutable) 객체입니다.
- 데이터를 추가하면 새로운 Context 인스턴스가 생성됩니다.
- 이는 데이터의 안전성을 보장하고 부수 효과를 방지합니다.
2.2 구독 범위
- Context는 구독별로 독립적으로 존재합니다.
- 하나의 Flux나 Mono에 여러 구독자가 있을 경우, 각 구독자는 자신만의 Context를 가집니다.
- 이를 통해 구독자별로 서로 다른 메타데이터를 관리할 수 있습니다.
3. Context 사용하기
3.1 Context 생성 및 데이터 추가
Context context = Context.of("user", "admin", "requestId", "123");
// 체이닝을 통한 데이터 추가
Context newContext = context.put("role", "ADMIN");
- of 메서드는 key/value 쌍을 인자로 받아 Context에 여러 개의 값을 추가할 수 있습니다.
- put 메서드는 기존 Context에 새로운 key/value 쌍을 추가한 새로운 Context를 반환합니다.
3.2 subscriberContext() / contextWrite() 사용
Flux<String> flux = Flux.just("data")
.contextWrite(context -> context.put("requestId", UUID.randomUUID().toString()))
.flatMap(data -> getRoleFromContext())
.contextWrite(Context.of("user", "admin"));
3.3 Context 데이터 읽기
Mono<String> mono = Mono.just("Hello")
.flatMap(data -> Mono.deferContextual(ctx ->
Mono.just(data + " " + ctx.get("user"))))
.contextWrite(Context.of("user", "John"));