★ 프로젝트 + 트러블 슈팅 ★
[JAVA] Spring @Scheduled
리승우
2022. 11. 24. 00:34
스케줄링 사용하기
스프링에서 스케줄링을 사용하기 위해서는 Main 클래스에 @EnableScheduling 어노테이션을 붙여줘야 한다.
@SpringBootApplication
@EnableScheduling
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
5초마다 현재 시간을 출력하는 코드를 작성해 보면 아래와 같다.
@Component
public class TestScheduler {
@Scheduled(cron = "0/5 * * * * *")
public void test() {
System.out.println("now: " + LocalDateTime.now());
}
}
코드를 작성하고 실행을 누르면 아래와 같이 5초마다 현재시각이 출력되는 것을 볼 수 있다.
1. cron 표현식
1
|
@Scheduled(cron = "0 30 23 * * *")
|
cs |
위의 시간은 매일 23시 30분으로 표현된 식이다.
문자열의 좌측부터 우측까지 순서대로 의미가 있고 각 항목은 space 문자로 구분한다.
자세한 사항은 아래와 같다.
순서 | 필드명 | 표현 가능한 값 |
1 | seconds | 0~59 , - * / |
2 | minutes | 0~59 , - * / |
3 | hours | 0~23 , - * / |
4 | day of month | 1~31 , - * ? / L W |
5 | month | 1~12 or JAN-DEC , - * / |
6 | day of week | 1-7 or SUN-SAT , - * ? / L # |
7 | years (optional) | 1970~2099 , - * / |
위처럼 자리수 마다 쓸수 있는 값들이 있다.
2. 특수문자 의미
특수문자 | 의미 | 사용예 |
* | 모든 수를 의미 | seconds에서 사용하면 매초, minutes에서 사용하면 매분, hours에서 사용하면 매시간 |
? | 해당 항목을 사용하지 않음 | day of month에서 사용하면 월중 날짜를 지정하지 않음. day of week에서 사용하면 주중 요일을 지정하지 않음 |
- | 기간을 설정 | hours에서 10-12이면 10시, 11시, 12시에 동작 minutes에서 58-59이면 58분, 59분에 동작 |
, | 특정 시간을 지정 | day of week에서 2,4,6이면 월,수,금에만 동작함 |
/ | 시작시간과 반복 간격 설정 | seconds위치에 0/15로 설정하면 0초에 시작해서 15초 간격으로 동작 minutes위치에 5/10으로 설정하면 5분에 시작해서 10분 간격으로 동작 |
L | 마지막 기간에 동작 day of month, day of week에서만 사용 |
day of month에서 사용하면 해당월 마지막 날에 수행 day of week에서 사용하면 토요일에 수행 |
W | 가장 가까운 평일 동작 day of month에만 사용 |
15W로 설정하면 15일이 토요일이면 가장 가까운 14일 금요일에 실행 15W로 설정하고 15일이 일요일이면 16일에 실행 15W로 설정하고 15일이 평일이면 15일에 실행 |
LW | L과 W의 조합 | 그달의 마지막 평일에 동작 |
# | 몇 번째 주와 요일 설정 day of week에 사용 |
6#3이면 3 번째 주 금요일에 동작 4#2이면 2번째 주 수요일에 동작 |
3. 사용예
표현식 | 의미 |
0 0 12 * * * | 매일 12시에 실행 |
0 15 10 * * * | 매일 10시 15분에 실행 |
0 * 14 * * * | 매일 14시에 0분~59분까지 매분 실행 |
0 0/5 14 * * * | 매일 14시에 시작해서 5분 간격으로 실행 |
0 0/5 14,18 * * * | 매일 14시, 18시에 시작해서 5분 간격으로 실행 |
0 0-5 14 * * * | 매일 14시에 0분, 1분, 2분, 3분, 4분, 5분에 실행 |
0 0 20 ? * MON-FRI | 월~금일 20시 0분 0초에 실행 |
0 0/5 14 * * ? | 아무요일, 매월, 매일 14:00부터 14:05분까지 매분 0초 실행 (6번 실행됨) |
0 15 10 ? * 6L | 매월 마지막 금요일 아무날이나 10:15:00에 실행 |
0 15 10 15 * ? | 아무요일, 매월 15일 10:15:00에 실행 |
* /1 * * * * | 매 1분마다 실행 |
* /10 * * * * | 매 10분마다 실행 |
4. fixedRate, fixedDelay
1
|
@Scheduled(fixedDelay = 3600000) // 1000 * 60 * 60, 즉 1시간마다 실행한다.
|
cs |
위의 예저처럼 사용할수있는데요. 5000 -> 5초이다.
fixedDelay : 지정된 시간 간격으로 작업을 실행 이전 수행이 시작된 시점부터 delay후에 재호출 (이전 수행이 완료된 시점부터 delay후에 재호출)
fixedRate : 지정한 시간 주기로 작업을 실행 (* 이전 수행의 종료를 기다리지 않고 수행됨)
예제 ) @Scheduled(fixedRate=5000) <- 이런경우 종료되기전에 5초마다 계속 수행된다.
두 가지의 차이점은 종료 후 실행되느냐 종료되기 전에 실행되느냐 차이!
예시
- 0 0 14 * * * : 매일 오후 2시
- 0 0 0 1 * * : 매달 1일 0시
- 0 5 1 ? 7 MON-WEB : 매년 7월 월-수 1시 5분
내가 적용한 코드
매월 21 ~ 30일, 8시 41분 0초에 실행되게 설정하였다.
Scheduler의 아쉬운점
1. void형식만 지원한다.
2. 매개변수를 넣을 수 없다.
@Scheduled(cron = "0 41 20 21-30 * *")
public void test() {
long rand = (long)(Math.random() * productRepository.count()) + 1;
LocalDateTime dateTime = LocalDateTime.now();
Product findProduct = productRepository.findById(rand).orElseThrow(
() -> new CustomCommonException(ErrorCode.NOT_FOUND_PRODUCT));
Event event = new Event(findProduct.getTitle(), "깜짝세일", "오늘만 특가예요", 100L, dateTime, dateTime.plusDays(1));
eventRepository.saveAndFlush(event);
}
}