728x90
Spring에서 @Async를 사용하면 비동기적으로 메서드를 실행할 수 있으며, 이를 통해 별도의 스레드에서 작업을 수행할 수 있습니다.
이를 위해 TaskExecutor와 ThreadPool을 함께 사용하여 효율적인 스레드 관리를 할 수 있습니다.
1. @Async 기본 사용법
@Async는 메서드를 비동기적으로 실행하게 만드는 애너테이션입니다. 이를 사용하려면 @EnableAsync를 설정해야 합니다.
사용 예시
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
@Service
public class AsyncService {
@Async
public void asyncMethod() {
System.out.println("비동기 작업 실행: " + Thread.currentThread().getName());
}
}
설정 클래스
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.EnableAsync;
@Configuration
@EnableAsync
public class AsyncConfig {
}
이제 asyncMethod()가 호출되면 별도의 스레드에서 실행됩니다.
2. TaskExecutor와 ThreadPool 설정
Spring에서 @Async가 실행될 때 사용할 스레드풀을 설정하려면 TaskExecutor를 정의해야 합니다.
스레드풀 설정
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import java.util.concurrent.Executor;
@Configuration
public class AsyncConfig {
@Bean(name = "customTaskExecutor")
public Executor taskExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(5); // 기본적으로 유지할 스레드 수
executor.setMaxPoolSize(10); // 최대 스레드 개수
executor.setQueueCapacity(100); // 대기 큐 크기
executor.setThreadNamePrefix("AsyncThread-");
executor.initialize();
return executor;
}
}
스레드풀 적용
@Service
public class AsyncService {
@Async("customTaskExecutor")
public void asyncMethod() {
System.out.println("비동기 작업 실행: " + Thread.currentThread().getName());
}
}
- "customTaskExecutor"를 명시하면 해당 스레드풀을 사용합니다.
- 설정하지 않으면 Spring의 기본 SimpleAsyncTaskExecutor가 사용됩니다.
3. 비동기 메서드에서 반환값 처리 (CompletableFuture)
비동기 메서드가 값을 반환해야 한다면 CompletableFuture를 사용할 수 있습니다.
예제
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import java.util.concurrent.CompletableFuture;
@Service
public class AsyncService {
@Async("customTaskExecutor")
public CompletableFuture<String> asyncMethodWithReturn() {
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
return CompletableFuture.completedFuture("비동기 작업 완료!");
}
}
호출 코드
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.concurrent.CompletableFuture;
@Component
public class AsyncCaller {
@Autowired
private AsyncService asyncService;
public void callAsyncMethod() {
CompletableFuture<String> future = asyncService.asyncMethodWithReturn();
future.thenAccept(result -> System.out.println("결과: " + result));
}
}
4. @Async 동작 방식 및 주의점
- 프록시 기반 동작
- @Async는 AOP 기반 프록시를 사용하므로 같은 클래스 내의 메서드에서는 @Async가 적용되지 않습니다.
- 해결책: 같은 클래스 내에서 사용하려면 별도의 빈으로 분리해야 합니다.
- 비동기 메서드는 public이어야 함
- 프록시를 통해 호출되므로 private 메서드에는 적용되지 않습니다.
- 트랜잭션(@Transactional)과 함께 사용할 때 주의
- @Async가 적용된 메서드는 별도 스레드에서 실행되므로, @Transactional이 적용된 경우 트랜잭션이 분리될 수 있습니다.
- 해결책: 트랜잭션을 유지하려면 같은 스레드 내에서 실행하도록 조정해야 합니다.
5. 정리
- @Async를 사용하면 메서드를 비동기적으로 실행할 수 있음.
- @EnableAsync를 설정해야 함.
- TaskExecutor를 설정하면 효율적인 스레드풀 관리 가능.
- 반환값이 필요하면 CompletableFuture 사용.
- 프록시 방식이므로 같은 클래스 내에서는 적용되지 않음.
이제 @Async, TaskExecutor, 그리고 ThreadPool을 활용하여 비동기 처리를 더욱 효과적으로 할 수 있습니다.
728x90
'개발 > Spring' 카테고리의 다른 글
| @Mock vs @MockBean 테스트 차이 (0) | 2025.02.19 |
|---|---|
| Spring HTTP 메소드 매핑 (0) | 2025.02.18 |
| @ControllerAdvice와 @ExceptionHandler를 사용한 글로벌 예외 처리 (0) | 2025.02.17 |
| Ajax File download(Spring boot) (0) | 2025.02.13 |
| Spring Boot & Maven Scope (compile, provided, runtime 등 차이점) (0) | 2025.02.13 |