🌟 Java 초보 개발자를 위한 비동기 체이닝 클래스 만들기: AsyncChain<T> 완전 분석
2025. 7. 2. 18:32ㆍSpring
반응형
이번에는 CompletableFuture를 더 쉽게, 더 깔끔하게 쓸 수 있도록 도와주는 AsyncChain<T> 클래스를 소개하고, 그 내부 동작을 하나하나 설명해드리겠습니다.
Java를 처음 배우다 보면 비동기 처리, 콜백 헬, 체이닝 같은 개념이 헷갈릴 수 있는데요. AsyncChain<T>는 이 복잡한 흐름을 마치 레고 조립하듯 직관적으로 이어갈 수 있도록 도와주는 클래스입니다.
🧩 AsyncChain<T>가 왜 필요할까?
Java에는 이미 CompletableFuture라는 강력한 비동기 API가 있지만...
- 체이닝할 때 코드가 복잡해지고
- 예외 처리, 병렬 처리 등에서 코드가 산으로 갈 수 있어요.
👉 그래서 만든 게 바로 AsyncChain<T>. CompletableFuture를 래핑(wrapping)해서 더 읽기 쉽고, 유지보수가 쉬운 방식으로 만들었어요.
🔨 기본 구조
public class AsyncChain<T> {
private final CompletableFuture<T> future;
private final ExecutorService executor;
// 기본 스레드 풀
private static final ExecutorService DEFAULT_EXECUTOR = ForkJoinPool.commonPool();
}
//설명:
T: 작업 결과의 타입입니다.
future: 실제 비동기 작업이 들어 있는 CompletableFuture.
executor: 스레드 실행을 담당하는 ExecutorService입니다.
🚀 시작하는 법
//1. 값으로 시작하기
AsyncChain.of(10)
//→ 10이라는 값을 가진 체인을 만들어줍니다. 마치 Future.completedFuture(10) 과 비슷하죠.
//2. 비동기 Supplier로 시작하기
AsyncChain.supply(() -> {
return 10 * 2;
})
//→ 내부적으로 CompletableFuture.supplyAsync(...)를 사용합니다. 계산은 비동기로 진행돼요.
🔗 체이닝 메서드
// 1. map(Function): 값 변환
AsyncChain.of(10)
.map(x -> x * 2) // 20
// → 동기적으로 값을 변환합니다. thenApply를 쓰고 있어요.
// 2. flatMap(Function): 체인을 이어붙이기
AsyncChain.of(10)
.flatMap(x -> AsyncChain.of(x * 3)) // 30
//→ 중첩된 AsyncChain을 펼쳐줍니다. thenCompose 사용.
// 3. peek(Consumer): 사이드 이펙트용
AsyncChain.of(10)
.peek(x -> System.out.println("결과: " + x))
// → 디버깅할 때 유용합니다. 값을 바꾸지는 않고, 그냥 엿보기만 해요.
// 4. doIf(Predicate, Consumer): 조건에 따라 실행
AsyncChain.of(10)
.doIf(x -> x > 5, x -> System.out.println("5보다 큽니다"))
// 5. filter(Predicate): 조건 필터링
AsyncChain.of(10)
.filter(x -> x > 5)
// → Optional<T>을 반환하는 체인으로 바뀝니다.
⛓️ 병렬 작업 (Parallel Execution)
// 1. 여러 개를 병렬로 실행하기
AsyncChain.supplyAll(() -> 1, () -> 2, () -> 3)
//→ 각 Supplier를 병렬로 실행한 뒤, 결과 리스트로 반환합니다.
// 2. 리스트에 대해 병렬로 map 하기
AsyncChain.ofAll(1, 2, 3)
.mapParallel(x -> x * 10) // [10, 20, 30]
// → mapParallel은 내부적으로 각 요소를 별도의 스레드로 실행합니다.
🛠️ 예외 처리
// 1. 실패 시 기본값 반환
AsyncChain.supply(() -> 1 / 0)
.orElse(-1) // 예외 발생 시 -1 반환
// 2. 실패 시 복구 함수 적용
.orElse(...) 대신 recover(...) 사용 가능
// 3. 재시도
AsyncChain.supply(() -> {
if (Math.random() < 0.7) throw new RuntimeException();
return "성공!";
}).retry(3, 1000) // 최대 3번 시도, 각 1초 간격
// → 실패하면 일정 시간 후 재시도합니다. 재시도 횟수가 남아 있으면 계속 해봐요.
// 4. 타임아웃
.timeout(2, TimeUnit.SECONDS)
// → 주어진 시간 내 완료되지 않으면 TimeoutException 발생.
🔚 결과 가져오기
.get() // 블로킹
.getNow(defaultValue) // 논블로킹
.onSuccess(result -> { ... }) // 성공 콜백
.onFailure(e -> { ... }) // 실패 콜백
🧠 핵심 요약
| 기능 | 메서드 |
| 기본 생성 | of, supply, supplyAll |
| 변환 | map, flatMap, mapParallel |
| 조건 처리 | filter, doIf, peek |
| 예외 처리 | recover, orElse, retry, timeout |
| 종료 처리 | get, getNow, onSuccess, onFailure |
🎁 마치며
이 AsyncChain<T> 클래스는 실무에서도 비동기 흐름을 깔끔하게 표현할 수 있도록 설계된 유틸리티입니다. 초보 개발자분들도 체이닝 방식에 익숙해지면, 복잡한 로직도 훨씬 명확하게 표현할 수 있어요.
반응형
'Spring' 카테고리의 다른 글
| Java 초보도 이해하는 비동기, 병렬 처리, 체이닝 그리고 AsyncChain<T>의 역할 (0) | 2025.07.02 |
|---|