📚 이전학습
Context in Reactive Programming 🌐
Context란? 🧩
- 정의: 비동기 작업 간에 상태 또는 데이터를 전달할 수 있도록 설계된 객체.
- 목적:
- 전역 상태를 대체
- 명시적이고 안전한 데이터 전달
- 요청 간 정보 공유를 위한 효율적인 방식 제공
- 사용 사례:
- 인증/인가 정보 전달
- 로깅 및 추적 데이터 전달
- 기본 설정 값 또는 환경 변수 전달
Context의 특징 🛠️
- 불변성
- Context 객체는 불변(immutable)으로 설계됨.
- 새 데이터를 추가하거나 제거할 경우 기존 Context는 변경되지 않고, 새로운 Context가 생성됨.
- Thread-Local 대체
- Context는 Thread-Local 변수와 유사한 역할을 하지만, 비동기/논블로킹 환경에서도 안전하게 사용할 수 있음.
- Thread-Local은 특정 스레드에 종속되지만, Context는 리액티브 체인 전체에 걸쳐 전달 가능.
- Key-Value 기반
- 데이터를 저장할 때 Key-Value 구조를 사용.
- 키를 통해 Context에 저장된 값을 조회할 수 있음.
Context 사용 방법 🧑💻
1. Context 생성
Context context = Context.of("key1", "value1", "key2", "value2");
2. Context와 Reactor 연동
- Context는 리액티브 체인에서 사용 가능하며,
Mono
또는Flux
와 통합 가능. Mono.deferContextual(ctx -> { String value = ctx.get("key1"); return Mono.just("Retrieved value: " + value); }) .contextWrite(Context.of("key1", "value1")) .subscribe(System.out::println);
// 출력: Retrieved value: value1
#### `contextWrite()`의 역할
- Context 데이터를 설정하거나 업데이트.
- 리액티브 체인의 특정 시점에서 Context를 변경 가능.
- ##### 단! DownStream ➡️ Upstream으로 전파되기 때문에 코드 상 subscribe 이전에 적어서 사용해야 함.
```java
Mono.deferContextual(ctx -> {
String value = ctx.get("key1");
return Mono.just("Retrieved value: " + value);
})
.contextWrite(Context.of("key1", "value1")) // context는 DownStream ➡️ Upstream으로 전파됨.
.subscribe(System.out::println);
// 출력: Retrieved value: value1
Context API 주요 메서드 📚
메서드 | 설명 |
---|---|
get(key) |
주어진 키에 해당하는 값을 반환. 없을 경우 예외 발생. |
getOrDefault(key, def) |
키가 존재하면 값을 반환하고, 없으면 기본값 반환. |
of(key, value...) |
Key-Value 쌍을 기반으로 Context 객체 생성. |
put(key, value) |
새로운 Key-Value 추가. 기존 Context를 변경하지 않고 새로운 Context 생성. |
Context 활용 사례 ✨
1. 인증 및 권한 정보 전달
Mono.deferContextual(ctx -> {
String token = ctx.getOrDefault("authToken", "default-token");
return Mono.just("Using token: " + token);
})
.contextWrite(Context.of("authToken", "Bearer abc123"))
.subscribe(System.out::println);
// 출력: Using token: Bearer abc123
2. 로깅 및 트랜잭션 추적
Flux.range(1, 5)
.flatMap(num -> Mono.deferContextual(ctx -> {
String traceId = ctx.get("traceId");
return Mono.just("TraceId: " + traceId + ", Number: " + num);
}))
.contextWrite(Context.of("traceId", "1234-5678"))
.subscribe(System.out::println);
// 출력 예시:
// TraceId: 1234-5678, Number: 1
// TraceId: 1234-5678, Number: 2
// ...
3. 기본 설정 및 환경 변수 전달
Mono.deferContextual(ctx -> {
String env = ctx.getOrDefault("env", "production");
return Mono.just("Running in environment: " + env);
})
.contextWrite(Context.of("env", "development"))
.subscribe(System.out::println);
// 출력: Running in environment: development
Context의 주의사항 ⚠️
1. 불필요한 데이터 남용
Context
에 과도한 데이터를 저장하면 성능 저하 초래 가능.- 필요한 정보만 최소한으로 저장.
2. Context 키 중복
- 동일한 키가 여러 번 사용되면 최신 값으로 덮어씀.
- 키 네이밍에 주의 필요.
3. 비동기 전환 시 Context 전파 누락
contextWrite()
이후에 새로운 스케줄러로 작업이 전환되면 Context가 손실될 수 있음.- Reactor의 Context Propagation 메커니즘을 올바르게 이해하고 사용.
예제 소스 📝
1. Context API 기본 예제
2. Context 특징 예제
- ContextFeatureExample01.java
- ContextFeatureExample02.java
- ContextFeatureExample03.java
- ContextFeatureExample04.java
3. Context 실제 활용 예제
4. Context 소개 예제
참고자료 📚
공식 문서
유용한 온라인 자료
🔗 GitHub Repository
•
자세한 학습 자료는 아래 GitHub 저장소를 참조하세요:
https://github.com/ses9892/learn_recator_programing/tree/main
'학습 > WebFlux' 카테고리의 다른 글
필터형 Operator - API (0) | 2024.12.03 |
---|---|
생성형 Operator - API (0) | 2024.12.03 |
Scheduler (1) | 2024.12.02 |
Sinks (0) | 2024.11.28 |
Backpressure (0) | 2024.11.27 |