@Async vs CompletableFuture

youngkyu MIn·2023년 10월 14일

비동기 처리를 위한 방법이지만 사용 방식과 특성이 약간 다르다.

@Async in Spring

  • Annotation-based: @Async는 스프링에서 제공하는 어노테이션으로, 메서드 레벨에서 비동기 실행을 지정한다.
  • Proxy-based: @Async는 스프링의 프록시 기반 메커니즘을 사용하여 비동기 실행을 한다. 따라서 스프링 빈에서만 사용할 수 있다.
  • Exception Handling: @Async 메서드에서 발생한 예외는 호출자로 전파되지 않는다. 이 예외들을 잡기 위해서는 @Async 메서드가 Future를 반환하고, 호출자가 이 Future에 접근할 때야만 발생한다.
  • Configuration: @EnableAsync를 사용하여 스프링의 비동기 지원을 활성화해야 한다.

CompletableFuture

  • Programmatic: CompletableFuture는 java.util.concurrent 패키지의 일부로, 프로그래매틱한 방식으로 비동기 작업을 정의한다. 어디서든 사용할 수 있다(스프링에 의존하지 않음).
  • API-based: CompletableFuture는 여러가지 비동기 프로그래밍 기능들을 API 형태로 제공한다.
  • Exception Handling: CompletableFuture를 사용하면 exceptionally() 또는 handle() 메서드를 이용하여 에러 핸들링을 할 수 있다.
  • Chainable API: CompletableFuture는 thenApply, thenCompose, thenAccept 등 메서드를 제공하여 Future의 결과를 체이닝해서 사용할 수 있다.

주요 차이점

  • Dependency: @Async는 스프링 기반 프로젝트에서만 사용할 수 있습니다. CompletableFuture는 자바 8 이상에서 사용할 수 있다.
  • Usage Style: @Async는 선언적이며, 메서드 레벨에서 사용한다. CompletableFuture는 코드 레벨에서 사용되며, 비동기 작업과 결과 처리를 한 곳에서 관리할 수 있다.
  • Flexibility: CompletableFuture는 비동기 작업을 조합하고, 결과를 변환하며, 예외를 핸들링하는 등의 다양한 API를 제공한다. @Async는 이러한 부분에서 제약이 있다.

CompletableFuture.runAsync() - void Method 에 사용
CompletableFuture.supplyAsync() - return 있는 Method 에 사용


CompletableFuture 사용 예

public CompletableFuture<RsData> send(String to, String subject, String body) {
        if (to.endsWith("@test.com")) return CompletableFuture.completedFuture(RsData.of("S-2", "메일이 발송되었습니다."));

        return CompletableFuture.supplyAsync(() -> {
            MimeMessage mimeMessage = mailSender.createMimeMessage();
            try {
                MimeMessageHelper mimeMessageHelper = new MimeMessageHelper(mimeMessage, false, "UTF-8");
                mimeMessageHelper.setTo(to); // 메일 수신자
                mimeMessageHelper.setSubject(subject); // 메일 제목
                mimeMessageHelper.setText(body, true); // 메일 본문 내용, HTML 여부
                mailSender.send(mimeMessage);
                return RsData.of("S-1", "메일이 발송되었습니다.");
            } catch (MessagingException e) {
                return RsData.of("F-1", "메일이 발송되지 않았습니다.");
            }
        });
    }
profile
한 줄 소개

0개의 댓글