@Async 와 비동기 대한 고찰
Spring의 @Async는 비동기적으로 메소드를 실행 한다.
비동기는 리턴값을 받을 수 없다.
그건 당연한 거다. 설사 받는다해도 null값이 떨어질 것이다.
한가지 받을 방법이 있는데 그게 바로 java.util.concurrent.Future 타입으로 받아야 된다.

@Async
public Future<String> getFuture() throws InterruptedException {
  return new AsyncResult<>("return");
}

이런 식으로 리턴 값을 받을 수 는 있다.
사용해 보자

Future<String> stringFuture = asyncBean.getFuture();
String result = stringFuture.get();

그런데 조금이상하다 비동기로 리턴값을 받으려면 getFuture이라는 메소드가 다 끝나야 받을 수 있는데 이상하다.
Future 있는 get을 호출할시 이 코드는 블럭킹 된다. 그럴수 밖에 없다. 그래야만 리턴값을 가질 수 있다.
한번 해보자

@Async
public Future<String> get() throws InterruptedException {
  System.out.println("sleep start");
  //오래 걸리는 작업 혹은 데이터베이스 조회
  TimeUnit.SECONDS.sleep(3);
  System.out.println("sleep end");
  return new AsyncResult<>("return");
}

위에는 만약 오래 걸리는 작업을 한다고 치자 예를 들어 데이터베이스를 조회해서 블록킹이 걸리거나 어떠한 복잡한 연산을 하기 위해 오래 걸린다고 하자.
그리고 나서 호출 해보자

Future<String> stringFuture = asyncBean.get();
System.out.println("비동기");
stringFuture.get();
System.out.println("end");

이렇게 호출 하면 어떻게 될까?
비동기가 아니라 동기라고 치자.

sleep start
sleep end
비동기
end

그럼 위와 같이 출력 될 것이다.
비동기면 어떨까?

비동기
sleep start
sleep end
end

이렇게 비동기가 먼저 출력된다. 맞다 get을 호출 하기 전까지는 비동기다. 하지만 get을 호출하면 블로킹이 걸린다.
만약 get함수를 없애보자

비동기
end
sleep start
sleep end

우리는 위와 같이 출력 되었다. 맞는 말이긴 하다 리턴을 받을려면 해당 함수가 끝나야 리턴이 가능하다 비동기던 동기던말이다.
그래서 우리는 리턴값을 받기위해 콜백 메소드를 만들곤 했다.
이렇게 말이다.

public interface Handler<E> {
  void handle(E e);
}

@Async
public void get(Handler<String> handler) throws InterruptedException {
  System.out.println("sleep start");
  //오래 걸리는 작업 혹은 데이터베이스 조회
  TimeUnit.SECONDS.sleep(3);
  System.out.println("sleep end");
  handler.handle("return");
}
asyncBean.get(i -> System.out.println(i));

어떻게 되든 우리는 리턴값을 받을 수는 있다. 하지만 용도가 다르다. 콜백과 Future는..
예를들어 오래 걸리는 작업을 빨리처리하고 결과와 상관 없이 응답을 빨리줘야 하는 상황이라면 콜백 메소드를 만드는 것이 낫다? 올바르다? 맞다?
그리고 특정한 많은 작업을 하고 그런 작업에 대한 응답을 줘야하는 상황이라면 Future를 쓰는 게 맞다.
많은 작업이라하면 공유하지 않는 어떠한 일들을 말하는 거다.
적절하게 자기에 맞는걸 잘 판단해서 사용 해야 될 것 같다.