Spring @Async
설정
Java 8 이후 버전에서는
AsyncConfigurer interface를 구현하면 된다. default method 라서 원하는 것만 선택구현가능함.
@EnableAsync
public class SpringAsyncConfig extends AsyncConfigurerSupport {
// 기본 taskExecutor
@Bean // @Bean 필수
@Override
public Executor getAsyncExecutor() {
return new ThreadPoolTaskExecutor(); // 객체 설정해줄것.
}
}
ThreadPoolTaskExecutor 설정
-
wait 설정으로 서버 종료시 남은 작업을 기다릴 시간 확보해야함. 아래를 안해주면 서버가 그냥 종료 돼 버린다.
waitForTasksToCompleteOnShutdown=true
awaitTerminationSeconds=초
beanName
을 지정해주면 로그에 이름이 찍힘.
-
-
Cached Thread Pool 효과
corePoolSize 는 적게 혹은 0, maxPoolSize=Interger.MAX_VALUE
, queueCapacity를 0으로 만들면 Cached Thread Pool 처럼 작동한다.
기본 CorePoolSize 만큼 풀을 생성하고,
필요하면 쓰레드풀을 최대 maxPoolSize 만큼 증가시키고
안 사용하는 시간이 KeepAliveSeconds가 지나면 쓰레드를 없앤다.
cachedThreadPool 은 느려지는 태스크 실행시 쓰레드 갯수가 폭증해서 시스템을 다운시킬 수도 있다.
ThreadPoolTaskExecutor threadPoolTaskExecutor = new ThreadPoolTaskExecutor();
threadPoolTaskExecutor.setThreadNamePrefix("XXXX-");
threadPoolTaskExecutor.setCorePoolSize(0);
threadPoolTaskExecutor.setMaxPoolSize(Integer.MAX_VALUE);
threadPoolTaskExecutor.setQueueCapacity(0);
threadPoolTaskExecutor.setKeepAliveSeconds(60);
threadPoolTaskExecutor.setWaitForTasksToCompleteOnShutdown(true);
threadPoolTaskExecutor.setAwaitTerminationSeconds(15);
MDC 사용하기
@Async
로 새로 생성된 쓰레드에서 호출자 쓰레드의
Slf4j MDC를 복제하도록 할 수 있다.
-
ThreadPoolTaskExecutor 설정에 Decorator 지정
@Override
public Executor getAsyncExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setTaskDecorator(new MdcTaskDecorator());
executor.initialize();
return executor;
}
MdcTaskDecorator.java
class MdcTaskDecorator implements TaskDecorator {
@Override
public Runnable decorate(Runnable runnable) {
// Right now: Web thread context !
// (Grab the current thread MDC data)
Map<String, String> contextMap = MDC.getCopyOfContextMap();
return () -> {
try {
// Right now: @Async thread context !
// (Restore the Web thread context's MDC data)
if (contextMap != null) {
MDC.setContextMap(contextMap);
}
runnable.run();
} finally {
MDC.clear();
}
};
}
}
CompletableFuture 지원
@Async
public CompletableFuture<User> findUser(String user) throws InterruptedException {
logger.info("Looking up " + user);
String url = String.format("https://api.github.com/users/%s", user);
User results = restTemplate.getForObject(url, User.class);
Thread.sleep(1000L);
return CompletableFuture.completedFuture(results); //IT IS completedFuture
}