본문 바로가기
스프링/스프링

[Spring] @Scheduled - 스프링에서 주기적인 작업을 진행하는 법

by 책 읽는 개발자_테드 2021. 5. 21.
반응형

스프링에서는 @Scheduled 어노테이션을 사용해서 주기적인 작업을 진행할 수 있다. 예를 들어 매일 아침마다 미정산 고객에게 결제를 시도하기, 일요일마다 고객에서 push 메세지 보내기 등을 할 수 있다.

 

이 글에서는 Spring 4.0 버전에서 XML 파일 설정을 통해 @Scheduled 기능을 사용한다.

 

학습 목표

- 초기설정

- Fixed Rate

- InitialDelay

- Cron Expression

- Parameterizing


 

초기 설정

1. 주기적인 작업을 수행할 클래스 생성

 

스프링 프로젝트에 다음과 같은 자바 코드를 추가한다.

import java.text.SimpleDateFormat;
import java.util.Date;

import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

@Component
public class ScheduleTasks {
	
	   @Scheduled(fixedDelay = 1000)
	   public void firstTask() {
	      SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");
	      Date now = new Date();
	      String strDate = sdf.format(now);
	      System.out.println("현재시간: " + strDate);
	   }
}

 

 

위에서 부터 차례대로 코드를 살펴보자. ScheduleTasks 클래스 선언 위에 @Component 어노테이션을 붙여서 해당 클래스를 스프링이 빈으로 인식할 수 있도록 한다. 클래스 내부에는 현재시간을 출력하는 firstTask() 메소드가 존재한다. firstTask() 메소드 위에는 @Scheduled(fixedDelay = 1000)라고하는 어노테이션이 존재한다. 이는 1초(1000ms)에 한 번 메소드를 실행한다는 의미한다. 

 

 

2. @Scheduled 설정을 사용하기 위한 XML 설정 

 

스프링 프로젝트 XML 설정에 @Scheduled 어노테이션을 사용하기 위한 코드를(빨간색) 추가한다. 위에서 작성한 ScheduleTasks.class를 인식하기 위한 component-scan 코드(파란색) 또한 추가한다.

<?xml version="1.0" encoding="UTF-8"?>

<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

xmlns:context="http://www.springframework.org/schema/context"

xmlns:task="http://www.springframework.org/schema/task"

xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd

        http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd

        http://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring-task-4.0.xsd">

 

<task:annotation-driven />    

    <context:component-scan base-package="xxxx">

    </context:component-scan>

</beans>

이제 @Scheduled 어노테이션 기능을 사용하기 위한 초기 설정은 끝이났다. 프로젝트를 실행하면 아래와 같이 1초에 한 번 firstTask() 메소드에 선언된 내용이 실행된다. 

지금까지 작성한 코드에서는 @Scheduled 어노테이션의 fixedDelay 옵션만을 사용했지만, 이외에도 여러가지 옵션이 존재한다. 이제부터 해당 옵션들을 알아보자.

 

Fixed Rate

다음과 같이 fixedDelay 옵션을 fixedRate로 변경하고, 코드를 실행해보자. 

import java.text.SimpleDateFormat;
import java.util.Date;

import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

@Component
public class ScheduleTasks {
	
	   @Scheduled(fixedRate = 1000)
	   public void firstTask() {
	      SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");
	      Date now = new Date();
	      String strDate = sdf.format(now);
	      System.out.println("현재시간:  " + strDate);
	   }
}

 

결과는 fixedDelay 옵션과 같이 1초에 한 번 firstTask 메소드를 실행하는것 처럼 보인다. 하지만 두 가지 옵션은 서로 다른 점이 있다.

 



fixedDelay 옵션은 이전 작업이 끝난 시점부터 x밀리초 이후마다 작업이 실행된다.

fixedRate 옵션은 이전 작업이 수행되기 시작한 시점부터 x밀리초 이후마다 작업이 실행된다.

 

위에서 작성한 작업처럼 시간이 얼마 걸리지 않는 작업에는 둘의 차이가 별로 없겠지만, 시간이 오래 걸리는 작업일수록 두 가지 옵션을 잘 비교해서 사용해야 한다.

 

initialDelay

작업을 최초로 시작하기 전 대기 시간을 정하고 싶다면, initialDelay를 설정할 수 있다. 다음은 스케줄러에 메서드가 등록된 후 처음 5초를 대기하고 1초마다 메서드를 실행하는 코드다.

import java.text.SimpleDateFormat;
import java.util.Date;

import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

@Component
public class ScheduleTasks {
	
	   @Scheduled(fixedDelay = 1000, initialDelay = 5000)
	   public void firstTask() {
	      SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");
	      Date now = new Date();
	      String strDate = sdf.format(now);
	      System.out.println("현재시간:  " + strDate);
	   }
}

 

Cron Expression(크론 표현식)

크론 표현식은 스케줄을 나타내기 위한 공백으로 나누어진 6개 또는 7개의 필드로 구성된 문자열이다. (연도 표시는 옵션이다.)

 

<seconds> <minutes> <hours> <days of month> <months> <days of week> <years>

 

각각의 필드에 입력할 수 있는 허용된 값들은 다음과 같다. 

표 끝의 특수문자의 의미도 알아보자

, : 여러 값을 추가할 때 사용한다. ex) MON, WED, FRI
- : 값의 범위를 정할 때 사용한다. ex) 10-12
* : 필드의 모든 값을 선택할 때 사용한다.
/ : 값의 증가를 설정할 때 사용한다. 예를 들어 seconds 필드에서 0부터 14씩 증가하는 값(0, 14, 28, 42)들을 선택할 수 있다. ex)0/14
? : 설정값 없음을 나타낸다. 
L : Last의 약어로 지정 범위의 마지막 값을 표시한다. ex)5L -> 마지막 금요일 
W : Weekday의 약어로 <days of month> 필드에서 주어진 날짜에서 가장 가까운 평일을 선택할 때 사용한다. 
# : N번 째 특정 요일을 설정할 때 사용한다. ex)5#2 -> 이 달의 두번째 목요일

 

크론 표현식을 @Scheduled 어노테이션에도 적용할 수 있다. 크론 표현식을 통한 코드를 작성해보자. 

import java.text.SimpleDateFormat;
import java.util.Date;

import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

@Component
public class ScheduleTasks {
	
	   @Scheduled(cron = "0 15 10 15 * ?")
	   public void firstTask() {
	      SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");
	      Date now = new Date();
	      String strDate = sdf.format(now);
	      System.out.println("현재시간:  " + strDate);
	   }
}

위 코드의 cron 옵션은 모든 달의 15일 오전 10시 15분에 작업을 실행한다는 의미다. 여기에 타임존 또한 설정할 수 있다.

import java.text.SimpleDateFormat;
import java.util.Date;

import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

@Component
public class ScheduleTasks {
	
	   @Scheduled(cron = "0 15 10 15 * ?", zone="Asia/Seoul")
	   public void firstTask() {
	      SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");
	      Date now = new Date();
	      String strDate = sdf.format(now);
	      System.out.println("현재시간:  " + strDate);
	   }
}

 

 

Parameterizing

@Scheduled 어노테이션의 설정 값을 외부에 두고, 매개변수화해서 사용할 수도 있다.

@Scheduled(fixedDelayString = "${fixedDelay.in.milliseconds}")

 

 

출처

http://docwiki.embarcadero.com/Connect/en/Writing_a_CRON_Expression

https://jeong-pro.tistory.com/186

https://www.baeldung.com/spring-scheduled-tasks

http://docwiki.embarcadero.com/Connect/en/Writing_a_CRON_Expression

 

반응형

댓글