이번 포스팅에서는 SpringBoot에서 ThreadPoolTaskExecutor를 어떻게 간단하게 설정하여 사용할 수 있는지 알려드립니다.
SpringBoot 프로젝트는 이미 구성되어 있다는 전제하에 Java11, SpringBoot 2.4.2 기준으로 작성했습니다.
참고로 ThreadPoolTaskExecutor의 설정 및 구체적인 사용법에 대해서는 이전에 포스팅한 문서를 참고하시기 바랍니다.
ThreadPoolTaskExecutor Bean 등록하기
우선 ThreadPoolTaskExecutor를 빈으로 등록하도록 하겠습니다.
TaskExecutorConfig 클래스를 만들고 @Configuration 어노테이션을 추가하여 설정을 위한 클래스를 하나 만들었습니다.
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
@Configuration
public class TaskExecutorConfig {
@Bean(name = "executor")
public ThreadPoolTaskExecutor executor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setThreadNamePrefix("my-");
return executor;
}
}
그리고 executor() 메서드를 하나 만들어서 ThreadPoolTaskExecutor를 생성하여 반환해주도록 하고 @Bean으로 등록하면서 name 속성을 지정해주었습니다. 참고로 name 속성의 값은 메서드명과 달라고 무관합니다. 또한, 해당 executor를 이용하여 쓰레드를 실행시켰을 때 내가 만든 ThreadPoolTaskExecutor가 사용되는 것인지 확인할 수 있도록 쓰레드명prefix를 "my-"로 세팅해주었습니다.
이전 포스팅을 읽어보셨거나 또는 ThreadPoolTaskExecutor를 직업 new 키워드로 생성해서 사용해보신 분은 눈치채셨을 수도 있을텐데요, 여기서 initialize()를 하지 않았습니다. 공식문서에는 initialize 메서드를 호출하는 것으로 나와있지만 굳이 하지 않아도 빈으로 등록될 때 initialize를 하더군요.
@Autowired 로 ThreadPoolTaskExecutor 사용하기
아래는 빈으로 등록한 executor를 서비스 레이어에서 autowired하여 사용하는 예제입니다.
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.stereotype.Service;
import lombok.extern.slf4j.Slf4j;
@Slf4j
@Service
public class TestService {
@Autowired
@Qualifier("executor")
private ThreadPoolTaskExecutor executor;
public void executeThreads() {
log.info("executing threads....");
Runnable r = () -> {
try {
log.info(Thread.currentThread().getName() + ", Now sleeping 10 seconds...");
Thread.sleep(10000);
} catch (InterruptedException e) {
e.printStackTrace();
}
};
for (int i = 0; i < 10; i++) {
executor.execute(r);
}
}
}
TestService라는 서비스 클래스에서 멤버변수 executor에 위에서 빈으로 등록한 객체를 쓰도록 @Qualifier로 executor 이름을 명시해주었습니다.
위 코드를 실행해보면 쓰레드 명이 my-1 로 출력되는 것을 확인하실 수 있습니다. corePoolSize를 default 값인 1 로 사용하여 싱글 쓰레드로 실행되기 때문에 my-2, my-3은 보이지 않습니다. corePoolSize 를 2 이상으로 세팅해주면 my-2, my-3 등의 쓰레드도 확인가능합니다.
2021-01-26 18:16:23.147 INFO 16390 --- [ my-1] com.keichee.test.service.TestService : my-1, Now sleeping 10 seconds...
2021-01-26 18:16:33.150 INFO 16390 --- [ my-1] com.keichee.test.service.TestService : my-1, Now sleeping 10 seconds...
2021-01-26 18:16:43.152 INFO 16390 --- [ my-1] com.keichee.test.service.TestService : my-1, Now sleeping 10 seconds...
2021-01-26 18:16:53.157 INFO 16390 --- [ my-1] com.keichee.test.service.TestService : my-1, Now sleeping 10 seconds...
@Async로 ThreadPoolTaskExecutor 사용하기
@Async 어노테이션을 이용하여 위에서 빈으로 등록한 ThreadPoolTaskExecutor를 사용하려면 @EnableAsync 도 추가해주어야 합니다.
따라서 TaskExecutorConfig 클래스에 @EnableAsync 어노테이션을 추가해줍니다.
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
@EnableAsync
@Configuration
public class TaskExecutorConfig {
@Bean(name = "executor")
public ThreadPoolTaskExecutor executor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setThreadNamePrefix("my-");
return executor;
}
}
그리고 서비스 레이어의 메서드를 하나 추가하겠습니다.
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import lombok.extern.slf4j.Slf4j;
@Slf4j
@Service
public class TestService {
@Async("executor")
public void task() {
try {
log.info(Thread.currentThread().getName() + ", Now sleeping 10 seconds...");
Thread.sleep(10000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
이제 controller 쪽에서 task() 메서드를 loop 돌면서 호출해보면 @Autowired 를 이용한 방법과 동일하게 로그가 출력되는 것을 확인하실 수 있을 겁니다.
이상으로 SpringBoot에서 ThreadPoolTaskExecutor 설정하여 사용하는 방법에 대해서 알아보았습니다.
간략하게 다시 정리해보자면
1. @Configuration 으로 등록한 클래스에 executor @Bean 추가 (@Async 를 이용할 경우 @EnableAsync 도 추가)
2. @Autowired @Qualifier 로 주입하여 사용하거나 또는 메서드 레벨에 @Async 를 붙여 사용
이렇게 정리할 수 있겠네요.
그럼 오늘도 행복한 코딩하세요~
'💻 Programming > Java' 카테고리의 다른 글
[5분코딩] Spring Boot Cache with EHCACHE (0) | 2022.09.14 |
---|---|
[Java] 자바 비동기 호출하기 (How to make asynchronous call in java) (0) | 2021.02.19 |
[Java] 자바 배열 리스트 맵 셋 정렬하기 (오름차순, 내림차순) (0) | 2021.01.21 |
[Java] 자바 예외/에러 처리 잘하기 (How to improve exception handling) (0) | 2020.12.08 |
[Java] 자바 2차원 배열 생성(선언 및 초기화) (0) | 2020.08.31 |