관리 메뉴

ballqs 님의 블로그

[Spring] @Async 란? 본문

코딩 공부/Spring

[Spring] @Async 란?

ballqs 2024. 10. 4. 14:34

Spring Boot의 @Async 이해 및 활용

@Async는 Spring에서 비동기 작업을 처리하는 기능을 제공하는 어노테이션입니다. 이 어노테이션을 메서드에 적용하면, 해당 메서드는 별도의 스레드에서 비동기적으로 실행됩니다. 이를 통해 메인 스레드의 작업이 차단되지 않으면서 동시에 다른 작업을 처리할 수 있어 애플리케이션의 성능과 응답성을 높일 수 있습니다.


@Async 동작 원리

Spring에서 @Async는 AOP(Aspect-Oriented Programming)와 스레드 풀을 활용하여 비동기 처리를 구현합니다. @Async가 붙은 메서드를 호출하면, Spring은 별도의 스레드를 생성하고 해당 메서드를 실행합니다. 이때, 메서드는 호출 즉시 반환되며, 메서드의 실제 실행은 백그라운드 스레드에서 처리됩니다.

  1. 스레드 풀: @Async가 붙은 메서드는 기본적으로 SimpleAsyncTaskExecutor를 사용하여 실행됩니다. 이 스레드 풀은 작업을 분배하여 다수의 스레드에서 병렬로 작업을 처리합니다. 기본적으로 새 스레드를 무제한으로 생성할 수 있지만, @EnableAsync와 함께 커스텀 스레드 풀을 설정하여 스레드 개수를 조절할 수 있습니다.
  2. 리턴 타입: @Async 메서드는 void, Future<T>, CompletableFuture<T>, ListenableFuture<T> 등의 리턴 타입을 가질 수 있습니다. Future나 CompletableFuture를 사용하면 비동기 작업의 결과를 기다리거나 작업 완료 후 특정 로직을 처리할 수 있습니다.

@Async 설정

기본 설정: @Async를 사용하려면, Spring Boot 애플리케이션에서 비동기 처리를 활성화해야 합니다. 이를 위해 메인 클래스 또는 설정 클래스에 @EnableAsync 어노테이션을 추가합니다.

@Configuration
@EnableAsync
public class AsyncConfig {
    // 스레드 풀 설정을 커스터마이징할 수 있음
}

 

사용법: 비동기 처리하고자 하는 메서드에 @Async 어노테이션을 적용합니다. 이 메서드는 호출 즉시 반환되고, 실제 처리는 백그라운드 스레드에서 수행됩니다.

@Service
public class AsyncService {

    @Async
    public void performAsyncTask() {
        System.out.println("비동기 작업 실행 중...");
    }
}

@Async 리턴 타입

  • void: 반환값이 없는 경우입니다. 메서드가 비동기로 실행되며 호출 즉시 반환됩니다.
  • Future<T>: 비동기 작업의 결과를 받을 수 있는 타입입니다. Future.get() 메서드를 사용하여 작업이 완료될 때까지 기다릴 수 있습니다.
  • CompletableFuture<T>: 자바 8 이상에서 사용할 수 있는 비동기 API로, 비동기 작업의 결과를 기다리지 않고도 추가적인 작업을 연결할 수 있습니다.
@Async
public CompletableFuture<String> fetchData() {
    // 비동기 처리 작업
    return CompletableFuture.completedFuture("작업 완료");
}

@Configuration 설정

@Configuration
@EnableAsync
public class AsyncConfig {

    @Bean(name = "customExecutor")
    public Executor taskExecutor() {
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        executor.setCorePoolSize(5);  // 기본 스레드 개수
        executor.setMaxPoolSize(10);  // 최대 스레드 개수
        executor.setQueueCapacity(500);  // 큐 사이즈
        executor.setThreadNamePrefix("AsyncThread-");
        executor.initialize();
        return executor;
    }
}

이렇게 설정한 후 @Async("customExecutor")와 같이 특정 메서드에 적용하여 사용할 수 있습니다.

 

주의사항

  • 트랜잭션: @Async 메서드는 기본적으로 호출한 메서드와 같은 트랜잭션 컨텍스트에 속하지 않습니다. 만약 트랜잭션 내에서 비동기 작업을 처리하려면 @Transactional과 함께 적절한 트랜잭션 전파 레벨을 설정해야 합니다.
  • 같은 클래스 내 호출: @Async 메서드는 프록시 기반으로 동작하므로, 같은 클래스 내에서 다른 메서드를 호출할 때는 비동기 처리가 이루어지지 않습니다. 이를 해결하려면 Spring의 AOP 구조에 맞게 별도의 빈을 통해 호출해야 합니다.

사용 예시

@Service
public class NotificationService {

    @Async
    public void sendNotification(String message) {
        // 오래 걸리는 작업을 비동기로 처리
        System.out.println("메시지 전송 중: " + message);
    }
}

 

이를 호출하는 클라이언트는 다음과 같이 @Async 메서드를 사용할 수 있습니다.

@RestController
public class NotificationController {

    private final NotificationService notificationService;

    public NotificationController(NotificationService notificationService) {
        this.notificationService = notificationService;
    }

    @GetMapping("/send")
    public String sendNotification() {
        notificationService.sendNotification("Hello!");
        return "알림 전송 요청됨!";
    }
}

 

이렇게 하면 /send 요청은 비동기로 처리되고, 클라이언트는 응답을 기다리지 않고 빠르게 응답을 받을 수 있습니다.