본문 바로가기

제안&정리

[Spring] 동일 클래스의 Async 호출하기

Spring에서는 @Async 어노테이션 기반으로 비동기 호출을 쉽게 할 수 있습니다.

 

다만 Proxy 기반으로 동작을 하다보니 동일 클래스의 다른 메서드에서 호출하는 경우

Proxy가 아닌 본래 메서드를 직접 호출하기 때문에 Async로 동작하지 않습니다.

 

이 때 클래스를 분리해서 해결할 수 있지만 비동기 처리만을 위해 클래스를 분리하기가 애매할 때가 많습니다.

이런 경우에는 아래와 같이 Async 처리만을 위한 별도 서비스를 두어 해결해 볼 수도 있습니다.

@Service
public class AsyncService {

  @Async
  public <R> CompletableFuture<R> callInternalMethodAsAsync(Supplier<CompletableFuture<R>> supplier) {
    return supplier.get();
  }

}

 

해당 서비스를 사용하는 코드는 아래와 같습니다.

@RequiredArgsConstructor
public class FooService {
  private final AsyncService asyncService;

  @Async
  public CompletableFuture<List<String>> findManyFooNames(List<Long> fooIds) {

    var fooNameFutures = fooIds.stream()
        .map(fooId -> asyncService.callInternalMethodAsAsync(
            () -> findFooName(fooId))
        ).toList();

    return CompletableFuture.completedFuture(
        fooNameFutures.stream()
            .map(AsyncUtils::get)
            .toList()
    );
  }

  @Async
  public CompletableFuture<String> findFooName(Long fooId) {
    return CompletableFuture.completedFuture("Bar" + fooId);
  }
}

 

AsyncUtils는 제가 편의를 위핸 만든 Util로 아래와 같은 형태로 되어 있습니다.

public class AsyncUtils {

  public static <R> R get(CompletableFuture<R> future) {
    try {
      return future.get();
    } catch (Exception e) {
      throw new CustomAsyncExecutionException(e);
    }
  }
}