최근에 업무하면서
TaskExecutor과 TaskScheduler를 모두 쓸 일이 있었다
그래서 개념에 대해서 깊게 보고싶어서
토비의 스프링을 펼쳐보았다^^7777
역시 이거만한게 없다..
정리해보쟛...ㅁ7ㅁ8
1. TaskExecutor
task실행기.. 그렇담 task는 뭘까?
Task : 독립적으로 실행한 가능한 작업
스프링은 이러한 task들을 다양하게 실행하도록 추상화하여 TaskExecutor라는 인터페이스를 제공한다.
package org.springframework.core.task;
import java.util.concurrent.Executor;
@FunctionalInterface
public interface TaskExecutor extends Executor {
void execute(Runnable var1);
}
java5의 Executor 인터페이스를 상속한다.
Runnable타입의 태스크를 받아 실행하는데,
다음 인터페이스는 독립적인 스레드에 의해 실행 되도록 의도된 오브젝트를 만들 때 주로 사용된다.
package java.lang;
@FunctionalInterface
public interface Runnable {
void run();
}
Spring의 TaskExecutor는 java.lang.concurrent 패키지 의 Executor와 똑같은 메소드를 가지고 있다.
package java.util.concurrent;
public interface Executor {
void execute(Runnable var1);
}
그럼에도 스프링에서 다시 만든이유는 다음과 같다.
1. 다른 기술의 태스크 실행기에 대한 어댑터를 제공 ( Quartz , CommonJ WorkManager...)
2. 스프링에 최적화된 방식의 태스크 실행기 확장
반드시 비동기 독립적 스레드에서 실행될 필요는 없지만 ,
대부분 비동기로 쓴닷 ㅎ_ㅎ
2. TaskExecutor 구현체
2.1 ThreadPoolExecutor
corePoolSize, maxPoolSize , queueCapacity 속성을 설정할 수 있다.
지정된 크기의 스레드 풀을 이용하며 , 작업 요청은 큐를 통해 관리된다.
가장 대표적인 태스크 실행기다.
@Bean
public Executor taskExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(5);
executor.setMaxPoolSize(5);
executor.setQueueCapacity(500);
executor.setThreadNamePrefix("async-");
executor.initialize();
return executor;
}
2.2 SimpleThreadPoolTaskExecutor
Quartz의 SimpleThreadPool을 이용해 만들어진 태스크 실행기이다.
2.3 WorkManagerTaskExecutor
CommonJ WorkManager의 태스크 실행기에 대한 어댑터이다.
2.4 SyncTaskExecutor
별도의 스레드에서 수행되는게 아니라 호출한 스레드 상에서 호출
3. TaskScheduler
다음 인터페이스는 주어진 태스크를 조건에 따라 실행하거나 반복하는 작업을 수행
태스크의 실행조건은
1) 특정시간
2) 일정한 간격을 두고 반복
3) Trigger인터페이스를 구현해서 유연한 조건
- > cron 서버의 실행시간 설정 포맷을 활용한 cronTrigger가 가장 대표적인 구현 클래스이다.
package org.springframework.scheduling;
import java.time.Duration;
import java.time.Instant;
import java.util.Date;
import java.util.concurrent.ScheduledFuture;
import org.springframework.lang.Nullable;
public interface TaskScheduler {
@Nullable
ScheduledFuture<?> schedule(Runnable var1, Trigger var2);
default ScheduledFuture<?> schedule(Runnable task, Instant startTime) {
return this.schedule(task, Date.from(startTime));
}
ScheduledFuture<?> schedule(Runnable var1, Date var2);
default ScheduledFuture<?> scheduleAtFixedRate(Runnable task, Instant startTime, Duration period) {
return this.scheduleAtFixedRate(task, Date.from(startTime), period.toMillis());
}
ScheduledFuture<?> scheduleAtFixedRate(Runnable var1, Date var2, long var3);
default ScheduledFuture<?> scheduleAtFixedRate(Runnable task, Duration period) {
return this.scheduleAtFixedRate(task, period.toMillis());
}
ScheduledFuture<?> scheduleAtFixedRate(Runnable var1, long var2);
default ScheduledFuture<?> scheduleWithFixedDelay(Runnable task, Instant startTime, Duration delay) {
return this.scheduleWithFixedDelay(task, Date.from(startTime), delay.toMillis());
}
ScheduledFuture<?> scheduleWithFixedDelay(Runnable var1, Date var2, long var3);
default ScheduledFuture<?> scheduleWithFixedDelay(Runnable task, Duration delay) {
return this.scheduleWithFixedDelay(task, delay.toMillis());
}
ScheduledFuture<?> scheduleWithFixedDelay(Runnable var1, long var2);
}
4. TaskScheduler 구현체
4.1 ThreadPoolTaskScheduler
JDK의 ShcdeuledThreadPoolExecutor 스케쥴러에 대한 어댑터이다.
@Bean
public TaskScheduler scheduler() {
ThreadPoolTaskScheduler scheduler = new ThreadPoolTaskScheduler();
scheduler.setPoolSize(10);
scheduler.setThreadNamePrefix("Scheduler-Thread-");
scheduler.initialize();
return scheduler;
}
4.2 TimerManagerTaskScheduler
참고) 유연한 조건을 이용!할때 쓰는 Trigger 인터페이스
package org.springframework.scheduling;
import java.util.Date;
import org.springframework.lang.Nullable;
public interface Trigger {
@Nullable
Date nextExecutionTime(TriggerContext var1);
}
그 Trigger 인터페이스를 구현한 CronTrigger CronExpression을 지원한다.
package org.springframework.scheduling.support;
import java.util.Date;
import java.util.TimeZone;
import org.springframework.scheduling.Trigger;
import org.springframework.scheduling.TriggerContext;
public class CronTrigger implements Trigger {
private final CronSequenceGenerator sequenceGenerator;
public CronTrigger(String expression) {
this.sequenceGenerator = new CronSequenceGenerator(expression);
}
public CronTrigger(String expression, TimeZone timeZone) {
this.sequenceGenerator = new CronSequenceGenerator(expression, timeZone);
}
public String getExpression() {
return this.sequenceGenerator.getExpression();
}
public Date nextExecutionTime(TriggerContext triggerContext) {
Date date = triggerContext.lastCompletionTime();
if (date != null) {
Date scheduled = triggerContext.lastScheduledExecutionTime();
if (scheduled != null && date.before(scheduled)) {
date = scheduled;
}
} else {
date = new Date();
}
return this.sequenceGenerator.next(date);
}
public boolean equals(Object other) {
return this == other || other instanceof CronTrigger && this.sequenceGenerator.equals(((CronTrigger)other).sequenceGenerator);
}
public int hashCode() {
return this.sequenceGenerator.hashCode();
}
public String toString() {
return this.sequenceGenerator.toString();
}
}
5. Annotaion 활용 ( @Scheduled , @Async )
5.1 @Scheduled
태스크 역할을 맡은 메소드에 직접 스케줄 정보를 어노테이션을 통해 부여해 수케줄이 적용되게 해준다.
@Scheduled 부여되는 메소드는 파라미터를 가질 수 없으며 반드시 void형 리턴 타입이어야한다.
- fixedDelay : 이전 작업이 끝난 시점부터 일정시간이 지난후에 동작하도록 설정 ,
이전 작업이 끝난후로 부터 정해진 시간이 지난후 다음작업이 시작된다.
@Schduled (fixedDelay=60000)
public void testFixedDelay(){...}
- fixedRate : 밀리초로 설정된 일정한 시간간격으로 메소드 실행
@Schduled (fixedRate=60000)
public void testFixedRate(){...}
- cron : Cron expression 으로 메소드 실행
@Schduled (cron = "0 0 12 1 * ?")
public void testCron(){...}
5.2 @Async
TaskExecutor를 코드로 사용하지 않고도 비동기 실행이 가능하게 해주는 어노테이션이다.
( 그런데 설정이 필요하면.. Bean으로 만들어주는게 좋다.. threadpool size 등등..)
리턴타입은 void 또는 Future 타입이어야한다.
메소드는 다른 코드에 의해 직접 호출 되므로 파라미터를 가질 수 있다.
더자세한 내용은 이전에 포스팅한 이글을 참조한다.
https://hyeonyeee.tistory.com/55
6. 결론
정리하다보니 더 자세히 이해가 되었다.
그리고 이전에 개발한 코드가 더 잘 와닿게 되었다 후후
그래서 한마디로 정리하자고 하면
TaskExecutor는 task를 주로 비동기적으로 처리할때 쓰고
TaskScheduler는 스케줄링할때 쓴다.
이 두개 모두 @Async , @Scheduled 라는 어노테이션으로 대체가 가능한데,
자세한 설정이 필요하면
bean으로 만들어 주는것이좋다~ (@Configuraion...)
그럼 정리 끝 -
'DEVELOP > Backend' 카테고리의 다른 글
[Spring] Application Event란? 업무에서 어떻게 이용 할 수 있을까? (0) | 2020.06.28 |
---|---|
[Spring] Async로 동작할때 Interceptor를 어떻게 탈까? (2) | 2020.06.11 |
Spring Security 에서 OAuth 2.0이란? (0) | 2020.05.18 |
JPA이란? (전체적인 개념, 느낀점) (0) | 2020.05.18 |
Django에서 Swagger 적용 (drf-yasg 쓰기 꼭^^;) (0) | 2020.03.26 |