용어 정리
caller :: 호출하는 함수
callee :: 호출당하는 함수
caller가 callee에게서 응답이 돌아올 때까지 대기합니다.
caller가 callee의 응답에 관심이 없기 때문에 호출 후, 대기하지 않습니다.
Application 클래스에 @EnableAsync 어노테이션을 적용하고, 비동기 처리를 사용하고자 하는 메서드에 @Async 어노테이션을 붙여 사용합니다.
그러나 이 경우에는 Thread Executor로 SimpleAsyncTaskExecutor를 사용하게 되는데, SimpleAsyncTaskExecutor는 비동기 작업마다 새로운 쓰레드를 생성하기 때문에 잘 사용하지 않습니다.
대신 AsyncConfig를 직접 정의하고, 메서드에 @Async 어노테이션을 붙여 사용합니다.
주의점
@Async어노테이션을 붙인 메서드는public접근 제어자를 사용해야 하며, self-invocation(같은 클래스 내부에서 메서드 직접 호출)이 불가능합니다.
@Async 어노테이션이 붙은 메서드들은 void, Future, ListenableFuture, CompletableFuture 중 하나의 반환 타입을 가져야 합니다.
반환 타입을 Future, ListenableFuture, CompletableFuture로 두는 경우에는 return 값을 받을 수 있습니다.
Future는 blocking 방식으로 동작하기 때문에 비동기 처리 시에 잘 사용하지 않습니다.
.isDone() 메서드를 통해 완료 여부를 boolean 값으로 확인 가능하고, .get()을 통해 결과를 가져올 수 있습니다.
ListenableFuture는 콜백을 통해 non-blocking 처리가 가능합니다.
addCallback() 메서드의 첫 번째 파라미터는 성공 시에 실행할 로직, 두 번째 파라미터는 실패 시에 실행할 로직을 지정해주면 됩니다.
CompletableFuture는 콜백을 통해 non-blocking 처리가 가능하며, 여러 비동기 작업을 조합하거나 체이닝할 수 있습니다.
Blocking Vs. Non-Blocking
Blocking은 callee가 작업을 마칠 때까지 caller의 작업이 Blocking 됩니다. (제어권은 callee가 가짐)
Non-Blocking은 callee의 작업과 상관없이 caller가 작업을 수행합니다. (제어권은 caller가 가짐)
비동기 메서드와 반환 타입을 CompletableFuture로 두는 예제 코드입니다.
회원가입 메서드는 로직 끝에 회원가입 쿠폰을 발급 메서드를 호출합니다.
쿠폰 발급 메서드는 회원가입 쿠폰을 저장해야 하지만 일부러 예외를 던지도록 했습니다.
회원가입 메서드에서 쿠폰 발급에 실패할 시의 동작을 정해뒀기 때문에 실패 로그가 남았습니다.