SmartLifeCycle
을 구현해줘야만 한다.@EnableAsync public class SpringAsyncConfig extends AsyncConfigurerSupport { // 기본 taskExecutor @Bean // @Bean 필수 @Override public Executor getAsyncExecutor() { return new ThreadPoolTaskExecutor(); // 객체 설정해줄것. } }
waitForTasksToCompleteOnShutdown=true
awaitTerminationSeconds=초
beanName
을 지정해주면 로그에 이름이 찍힘.Interger.MAX_VALUE
, queueCapacity를 0으로 만들면 Cached Thread Pool 처럼 작동한다. 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);
@Async
로 새로 생성된 쓰레드에서 호출자 쓰레드의 Slf4j MDC를 복제하도록 할 수 있다.@Override public Executor getAsyncExecutor() { ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor(); executor.setTaskDecorator(new MdcTaskDecorator()); executor.initialize(); return executor; }
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.completedFuture()
를 리턴하게 만들면 Spring 이 내부적으로 AsyncExecutionInterceptor에서 진짜 CompletableFuture.supplyAsync
로 변환해서 리턴한다. AsyncExecutionAspectSupport.java 소스 ListenableFuture와 Future도 마찬가지로 작동함.@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 }