Spring 기본설정
으로 되어 있는 TaskExecutor
는 SimpleAsyncTaskExecutor
입니다.SimpleAsyncTaskExecutor
에서는 어떤 스레드도 재사용하지않고
호출마다 새로운 스레드를 시작합니다.
저는 AsyncConfigurer를 사용해서 공통된 Thread Pool을 사용하는 방법
을 쓸 것입니다.
getAsyncExecutor
method를 override 합니다.기본 구조는 아래와 같습니다.
@Async
를 사용해서 다른 스레드에서 돌리고자 한다면 @EnableAsync
설정을 해야 합니다.//기본 구조
@EnableAsync
@Configuration
public class AsyncConfigure implements AsyncConfigurer {
}
ThreadPoolTaskExecutor
를 사용했습니다.ThreadPoolTaskExecutor
//Sample Code
@EnableAsync
@Configuration
public class AsyncConfigure implements AsyncConfigurer {
@Override
public Executor getAsyncExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setThreadNamePrefix("async-thread-");
executor.setCorePoolSize(10);
executor.setMaxPoolSize(50);
executor.setQueueCapacity(100);
executor.setRejectedExecutionHandler(new ThreadPoolExecutor.AbortPolicy());
executor.initialize();
return executor;
}
}
@Async
는 기본적으로 method의 return value가 void인 경우만 적용됩니다.CompletableFuture
를 사용해야 합니다.@Async
어노테이션을 사용하고 return value는 CompletableFuture를 사용합니다.//기본 구조
@Async
@GetMapping(path = "_hcheck")
public CompletableFuture<Long> healthCheck() {
return CompletableFuture.completedFuture(healthCheckService.healthCheck());
}
아래 세 가지를 조합하여 멀티쓰레드 환경(쓰레드 풀 사용)에서 Async-NonBlocking 방식으로 요청을 처리하고 return value를 받을 수 있도록 완성하였습니다.
@Async
Thread Pool(AsyncConfigurer)
CompletableFuture
아래는 샘플 소스를 첨부하였습니다.
//HealthCheckRestController
@RequestMapping("api")
public class HealthCheckRestController {
private final HealthCheckService healthCheckService;
@Async
@GetMapping(path = "_hcheck")
public CompletableFuture<Long> healthCheck() {
return CompletableFuture.completedFuture(healthCheckService.healthCheck());
}
}
//HealthCheckService
@Service
public class HealthCheckService {
public Long healthCheck() {
return System.currentTimeMillis();
}
}
//AsyncConfigure.java
@EnableAsync
@Configuration
public class AsyncConfigure implements AsyncConfigurer {
@Override
public Executor getAsyncExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setThreadNamePrefix("async-thread-");
executor.setCorePoolSize(10);
executor.setMaxPoolSize(50);
executor.setQueueCapacity(100);
executor.setRejectedExecutionHandler(new ThreadPoolExecutor.AbortPolicy()); //추후 설명
executor.initialize();
return executor;
}
}