최근에 업무하면서

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

 

Spring에서 Async 처리 (@Async )

Spring에서 Async처리를 해보겠다..! 블로그에 정리되어 있는게 많았는데 그중에 어떤 방법을 택할까 고민을 했다. 가장 간단한 방법으로 구현하였다. @Async annotaion을 붙여주는 방법이다. 1. @EnableAsyn

hyeonyeee.tistory.com

 

 

 


6. 결론

 

정리하다보니 더 자세히 이해가 되었다.

그리고 이전에 개발한 코드가 더 잘 와닿게 되었다 후후

 

그래서 한마디로 정리하자고 하면

 

TaskExecutor는 task를 주로 비동기적으로 처리할때 쓰고

TaskScheduler는 스케줄링할때 쓴다.

 

이 두개 모두 @Async , @Scheduled 라는 어노테이션으로 대체가 가능한데,

자세한 설정이 필요하면

bean으로 만들어 주는것이좋다~ (@Configuraion...)

 

그럼 정리 끝 - 

스프링에서 Filter, Interceptor, AOP는 모두 어떤 동작 이전/이후에 추가적으로 처리해주어야 할때 사용한다.

기능적으로는 비슷한데 내부 구현적으로는 차이가 있다.

 

Filter, Interceptor : Sevlet 단위에서 실행

AOP : 메소드 앞에 proxy 패턴의 형태로 실행

 

그래서 실행 순서도 차이가 있다 ???

 

Filter -> Interceptor -> AOP -> Interceptor -> Filter 순이다

이미지 참조 : blog.naver.com/platinasnow/220035316135

 

Request -> Servlet Filter -> Dispatcher Servlet -> HandlerInterceptor -> Controller

 

1. 서버를 기동시켜 서블릿이 올라오는 동안 init 실행 되고 FilterdoFilter 실행

2. 컨트롤러 이전에 InterceptorpreHandler실행

3. 컨트롤러 빠져나온다음 InterceptorpostHandler, afterCompletion 실행

4. FilterdoFilter 진행

5. 서블릿 종료시 destroy 실행

 

AOP는 주로 비지니스 로직단에서 로깅,트랜잭션, 공통예외처리 에서사용한다.

 

 

참고

hayunstudy.tistory.com/53

 

# Filter , Interceptor , AOP 사용목적 정리

Filter,Interceptor,AOP 모두 요청 중간에 가로채서 사전처리,사후처리를 하는 의미는 비슷하다. 로깅처리 또한 셋다 가능. 차이점이라고 하면 , 1. 셋의 시점이 다르다는것 : Filter -> Interceptor -> AOP 2. 적

hayunstudy.tistory.com

junshock5.tistory.com/142

 

Filter, Intercepter, AOP 차이점

[ 배경 ] 자바 웹 개발을 하다 보면, 공통적으로 처리해야 할 업무가 생깁니다. 예를 들어 로그인 관련 세션 처리, 사용자 권한 체크, XSS(Cross Site Script) 방어 로직, PC Mobile 플랫폼 분기 처리, 로그

junshock5.tistory.com

 

+ Recent posts