Spring

몽수의 Spring Scheduler

기몽수 2024. 7. 28. 22:48

스프링 스케줄러(Spring Scheduler)

 

 

스프렝 스케줄러란?

  • Spring Framework에서 제공하는 기능
  • 특정 작업을 주기적으로 실행할 수 있도록 지원한다.
  • 이를 통해 배치 작업이나 정기적인 백그라운드 작업을 간편하게 설정할 수 있다.
  • @Schedlued 어노테이션을 사용하여 설정한다.

 

스프링 스케줄러의 기본 개념

1. 스케줄링이란?

  • 스케줄링은 특정 시간 간격이나 특정 시간에 작업을 실행하는 것을 의미한다.
  • 예를 들어, 매일 자정에 데이터 백업 작업을 실행하거나 매 시간마다 로그 파일을 정리하는 작업을 설정할 수 있다.

 

2. 스프링 스케줄러의 주요 기능

  • 주기적으로 반복되는 작업을 설정할 수 있다.
  • 고정된 간격으로 작업을 실행하거나, 특정 시간에 작업을 실행하는 등 다양한 스케줄링 옵션을 제공한다.
  • 별도의 스레드에서 작업을 실행하며 메인 애플리케이션의 흐름에 영향을 주지 않는다.

 

 


 

스프링 스케줄러 설정 방법

 

1.  스케줄링 활성화

스프링 스케줄러를 사용하려면 설정 클래스에 @EnableScheduling 어노테이션을 추가하여 스케줄러 기능을 활성화해야한다.

import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.EnableScheduling;

@Configuration
@EnableScheduling
public class SchedulerConfig {
    // 추가 설정 필요 시 여기에 작성
}

 

 

2. 스케줄링 메서드 작성

  • 스케줄링 할 작업을 담는 메서드 @Scheduled 어노테이션을 추가한다.
  • @Scheduled 어노테이션의 속성을 사용하여 작업 실행 간격이나 실행 시간을 설정할 수 있다.

 


 

@Scheduled 어노테이션

이 어노테이션을 통해 다양한 속성을 사용하여 작업 스케줄을 설정한다. 주요 속성은 다음과 같다.

 

1. fixedRate

  • 고정된 시간 간격(밀리초 단위)으로 작업을 실행한다.
  • 이전 작업이 완료되었는지 여부와 상관없이 설정된 간격으로 작업을 실행한다.
@Scheduled(fixedRate = 5000)
public void fixedRateTask() {
    System.out.println("Fixed rate task - " + System.currentTimeMillis() / 1000);
}

-> 이 메서드는 매 5초마다 실행됨

 

 

2. fixedDelay

  • 이전 작업이 완료된 후 고정된 시간 간격(밀리초 단위)으로 작업을 실행한다.
  • 이전 작업이 완료된 시점부터 설정된 간격으로 작업을 실행한다.
@Scheduled(fixedDelay = 5000)
public void fixedDelayTask() {
    System.out.println("Fixed delay task - " + System.currentTimeMillis() / 1000);
}

 

-> 이 메서드는 이전 실행이 완료된 후 5초의 지연시간을 두고 메서드가 다시 실행됨

 

3. cron

  • 크론 표현식을 사용하여 작업을 스케줄링한다.
  • 크론 표현식은 초, 분, 시간, 일, 월, 요일을 조합하여 특정 시간에 작업을 실행할 수 있다.
@Scheduled(cron = "10 0 * * * *")
public void cronTask() {
    System.out.println("Cron task - " + System.currentTimeMillis() / 1000);
}

cron = "초, 분, 시간, 일, 월, 요일"

-> 이 메서드는 매 10초마다 실행됨

 

종합 예제

import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

@Configuration
@EnableScheduling // 스케줄링 기능 활성화
public class SchedulerConfig {
}

@Component
public class ScheduledTasks {

    // 매 5초마다 실행
    @Scheduled(fixedRate = 5000)
    public void fixedRateTask() {
        System.out.println("Fixed rate task - " + System.currentTimeMillis() / 1000);
    }

    // 이전 작업이 완료된 후 5초 후에 실행
    @Scheduled(fixedDelay = 5000)
    public void fixedDelayTask() {
        System.out.println("Fixed delay task - " + System.currentTimeMillis() / 1000);
    }

    // 매 분 0초에 실행
    @Scheduled(cron = "0 * * * * *")
    public void cronTask() {
        System.out.println("Cron task - " + System.currentTimeMillis() / 1000);
    }
}

 

 

스프링 스케줄러의 주의 사항

  1. 스케줄링된 메서드는 void 반환 타입을 가져야 하며, 매개변수를 가지지 않아야 한다.
  2. 스케줄링된 메서드 내부에서 예외가 발생하면 스케줄러는 해당 작업을 다시 시도하지 않는다.
  3. 스케줄링 작업이 오래 걸리는 경우 별도의 스레드풀을 구성하거나 비동기 처리를 고려해야한다.

 


 

 

스프링 스케줄러의 동작 과정

 

1. ScheduledAnnotationBeanPostProcessor 클래스가 Bean으로 등록됨

- 스프링 애플리케이션이 시작되면, 스프링 컨텍스트는 ScheduledAnnotationBeanPostProcess 클래스를 빈으로 등록한다.

- 해당 어노테이션이 붙은 클래스는 @Scheduled 어노테이션이 붙은 메서드를 스켄하고 관리하는 역할을 한다.

@Configuration
@EnableScheduling
public class SchedulingConfig {
    // 스케줄링 설정 클래스
}

 

 

2. postProcessAfterInitialization() 메서드 실행

- ScheduledAnnotationBeanPostProcessor는 스프링 빈이 초기화 된 후 postPorcessAfterInitialization() 메서드 실행

- 이 메서드는 모든 빈을 스캔하여 @Scheduled 어노테이션이 붙은 메서드를 찾고, 이를 내부 맵에 저장한다.

@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
    if (!this.processScheduled(bean)) {
        return bean;
    }
    return proxyScheduledMethods(bean);
}

 

 

3. processScheduled() 메서드 호출

- postProcessAfterInitialization() 메서드는 processScheduled() 메서드를 호출하여 @Scheduled 어노테이션이 붙은 메서드를 처리한다.

- 이 메서드는 스케줄링된 메서드를 찾아서 적절한 스케줄링 정보를 설정한다. 

private boolean processScheduled(Object bean) {
    // @Scheduled 어노테이션이 붙은 메서드를 처리
}

 

 

4. processScheduled() 메서드에서 작업 스케줄링

- processScheduled() 메서드는 @Scheduled 어노테이션의 속성(cron, fixedReate, fixedDelay)에 따라 작업 스케줄링

- 여기서는 cron 속성을 사용하는 경우를 예로 설명한다. 

private void processScheduled(Object bean) {
    // @Scheduled 어노테이션의 속성에 따라 작업을 스케줄링
    if (cron != null) {
        this.scheduledTaskRegistrar.scheduleCronTask(new CronTask(runnable, cron));
    }
}

 

 

5. ScheduledTaskRegistrar.scheduleCronTask() 호출

- processScheduled() 메서드는 ScheduledTaskRegistrar의 scheduleCronTask() 메서드를 호출하여 작업을 스케줄링

- 이 메서드는 작업과 크론 표현식을 받아서 스케줄링 작업을 등록

public void scheduleCronTask(CronTask task) {
    this.scheduledCronTasks.add(task);
    this.scheduleCronTask(task.getRunnable(), task.getExpression());
}

 

 

6. ScheduledExecutorService에 작업 등록

- ScheduledTaskRegistrar는 ScheduledExecutorService의 구현체에 작업과 딜레이 정보를 넘겨 작업을 등록

- ScheduledExecutorService는 작업을 실행할 스레드 풀을 관리한다.

ScheduledExecutorService executor = Executors.newScheduledThreadPool(poolSize);
executor.schedule(() -> {
    // 작업 실행
}, delay, TimeUnit.MILLISECONDS);

 

 

 

7. Delay가 지나면 작업 실행

- ScheduleExecutorService는 설정된 딜레이가 지나면 스레드 풀에서 스레드를 할당하여 작업의 run() 메서드를 실행한다.

- 이 메서드는 스케줄링된 작업을 실제로 실행한다.

executor.schedule(() -> {
    // 작업 실행
}, delay, TimeUnit.MILLISECONDS);

 

 

 

8. 작업 재등록

- 작업이 실행된 후 run() 메서드는 ScheduleExecutorService에 작업을 다시 등록하여 주기적으로 실행한다.

- 이로 인해 작업은 설정된 딜레이 후에 다시 실행

executor.schedule(() -> {
    // 작업 실행 후 다시 등록
}, delay, TimeUnit.MILLISECONDS);

 

 

9. 무한 반복

 

 


 

요약된 동작 과정

1. 스프링 컨텍스트 초기화: 스프링 부트 애플리케이션이 시작될 때 스프링 컨텍스트가 초기화

2. @EnableScheduling 확인 : 스프링 컨텍스트는 @EnableScheduling 어노테이션이 붙은 클래스를 찾아 스케줄링 기능을 활성화

3. ScheduledAnnotationBeanPostProcessor 등록 : 스프링 컨텍스트는 해당 클래스는 빈으로 등록한다.

4. 3번에서 빈으로 등록한 클래스를 생성 후 postProcessAfterInitialization() 메서드 실행

5. @Scheduled 메서드 스캔 : postProcessAfterInitialization()가 실행되어 스프링 컨텍스트에서 모든 빈을 스캔하여 @Scheduled 어노테이션이 붙은 메서드를 찾아내고, 이를 내부 맵에 저장한다.

6. processScheduled() 호출: postProcessAfterInitialization()에서 호출된 메서드로 스케줄링 정보를 설정해준다.

7. cron, fixedDelay등 옵션에 따라 알맞는 Task 진행한다.

8. ScheduledTaskRegistrar : 스케줄링 작업을 등록한다.

9. ScheduledExecutorService : ScheduledTaskRegistrar에 등록된 작업을 주기적으로 실행 시켜준다.

  • 딜레이가 지나면 작업 실행
  • 작업 실행 후 다시 등록
  • 무한 반복