@Async로 비동기 처리

이건우·2025년 4월 2일

웹 프로그래밍

목록 보기
41/43

비동기란 무엇일까?

어떤 작업이 완료될 때까지 기다리지 않고,
그 작업이 끝나는 동안 다른 작업을 계속 수행할 수 있는 방식입니다.
JAVA 구조로 이해하자면 메소드A와 메소드B가 있을 떄,
메소드A가 비동기 메소드라면 메소드A의 실행 종료를 기다리지 않고
메소드B를 실행 할 수 있게 되는 형식입니다.

비동기, 언제 사용할까?

비동기의 가장 효율적인 사용 방법은 현재 수행되는 시퀀스가
해당 동작과의 직접적인 연관이 없는, 즉, 결과값이 필요 없는 경우에 가장 효율적으로
동작 할수 있습니다.

예를 들어, 회원가입시에 본인 인증 메일을 보내는 비동기 메소드를 사용하여,
회원가입의 시퀀스 중에 인증 메일을 보내는 시간 만큼을 감소 시키는 등의 형식입니다.

슬랙 알림, 로그 저장, 외부 API 호출 등 수행 시퀀스 내에서 직접적으로
응답이 필요 없는 경우에 사용하여 API의 응답시간을 단축 시킬수 있습니다.

@Async는 어떤 어노테이션일까?

@Async는 Spring에서 메서드를 비동기로 실행할 수 있게 해주는 기능으로,
약간을 설정을 통해 사용 할 수 있습니다.

사용 방법

1. @EnableAsync로 비동기 기능 활성화

먼저 비동기 기능을 사용하겠다는 설정이 필요합니다.

@Configuration
@EnableAsync
public class AsyncConfig {
    // ThreadPool 설정 여기서
}

별도의 ThreadPool 관리에 대한 설정도 가능하니
필요하다면 설정해 주도록 합니다.

2. @Async 붙이기

설정이 완료되었으면 이제 특정 메소드에 @Async를 추가해
비동기적으로 수행 되도록 합니다.
별도의 스레드에서 비동기적으로 실행돼서 호출한 쪽은 기다리지 않게 되는 것입니다.

@Service, @Component 등 Spring Bean에 붙은 클래스여야 합니다.

@Service
public class NotificationService {

    @Async
    public void sendEmail(String email) {
        // 메일 전송 로직
        System.out.println("메일 전송 완료 : " + email);
    }
}

3. 비동기 메서드 호출

@RestController
@RequiredArgsConstructor
public class UserController {

    private final NotificationService notificationService;
	private final UserService userService;
    
    @PostMapping("/signup")
    public ResponseEntity<?> signup(@RequestBody String email) {
    	// 회원가입 로직
        notificationService.sendEmail(email); // 비동기로 메일 전송
        return ResponseEntity.ok("회원가입 완료!");
    }
}

notificationService.sendEmail(email); 이 비동기로 실행되기 떄문에
해당 메소드의 실행을 기다리지 않고
바로 응답을 보내게 됩니다.

++ 비동기 메소드의 리턴값

비동기 메서드에서 결과를 반환받고 싶을 때는 Future나 CompletableFuture를 사용,
효율이 떨어지기는 하나 결과를 반환받는 방식으로 사용 할 수도 있습니다.

메소드 선언부
작업을 수행 한 후에 비동기 객체를 반환합니다.

@Async
public CompletableFuture<String> getDataAsync() {
    // 수행작업
    return CompletableFuture.completedFuture("리턴할 데이터");
}

메소드 사용부
반환받은 비동기 객체를 .get으로 작업이 완료 될 때 까지 대기합니다.

CompletableFuture<String> result = service.getDataAsync();
String value = result.get();

++ 주의점

@Async는 프록시 기반으로 동작합니다.
즉, Spring AOP의 프록시 메커니즘을 사용,
비동기 쓰레드에서 해당 메서드를 실행되도록 하는 것이기에
프록시가 가로채지 못하면 비동기적 실행이 불가능 합니다.

꼭 Spring Bean이 붙은 클래스 내부에서 사용해야 하는 것도 이러한 맥락입니다.
같은 이유로 this.메소드()도 사용이 불가능하니,
프록시 기반인 것을 염두해 두고 사용하여야 합니다.

profile
새싹개발자

0개의 댓글