프로젝트 진행 중 기간 만료 기프티콘 상태 업데이트, 폐업 예정 일자 도래 시 폐업 처리 등등 일정 시간마다 이를 처리해주는 과정이 필요했다.
원래는 @Scheduled 어노테이션을 적용해 코드를 바로 수정하려고 했다. 하지만 이 어노테이션에 대해 찾아보다 보니 여러 방법이 있는 것 같았고, 좀 더 확실히 알아보고 적합한 방법을 선택해야겠다는 생각이 들었다.
매번 요청을 받지 않아도 일정 시간 후 또는 주기를 갖고 어떤 작업을 반복 수행할 수 있는 도구.
장점
단점
장점
단점
이 정도로 알아보고, 내가 구현할 기능은 Spring Scheduler로 충분하다는 판단이 되었다. Spring Quartz는 현재 추후에 분산 시스템에서 적용해 보면 좋을 것 같다.
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.domain.EntityScan;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
import org.springframework.scheduling.annotation.EnableScheduling;
@SpringBootApplication
@EnableScheduling
@EnableDiscoveryClient
public class SoconApplication {
public static void main(String[] args) {
SpringApplication.run(SoconApplication.class, args);
}
}
프로젝트 패키지들이 존재하는 경로에 scheduler 패키지 생성 후, 클래스를 하나 생성해줬다.
클래스는 스프링 빈으로 등록되어야 한다
이를 위해서 다음 세 가지 방법 중 하나를 취할 수 있다.
1. @Component 어노테이션 추가
2. xml 설정 파일로 등록
3. JavaConfig를 이용해 등록
보통 @Component 어노테이션을 많이 사용한다고 한다
스프링 빈으로 등록하는 이유
1. 의존성 주입: 스케쥴러 클래스가 스프링 빈으로 등록되면, 다른 스프링 빈에 주입될 수 있음. 이를 통해 다른 빈과 상호작용할 수 있음
2. @Scheduled 어노테이션은 스프링 빈의 메서드에 적용됨
3. 스프링 컨테이너가 생명주기를 관리함. 필요시점에 생성, 소멸시킬 수 있음
4. 테스트 코드에서 쉽게 mock 객체로 대체할 수 있음.
@Component 어노테이션으로 빈으로 등록해 준 다음 실행할 메소드에는 @Scheduled 어노테이션으로 스케줄링을 설정할 수 있다.
cron, fixedDelday, fixedRate로 메소드 실행 간격을 설정할 수 있다.
cron 표현식
(cron = "* * * * * *")
순서대로 초 분 시 일 월 요일 을 지정할 수 있다.
요일: 0~6까지 일, 월, 화, ..., 토.
* : 매 (단위) ex. 매초, 매분, 매시, 매일 ...
? : 날짜와 요일에서만 사용 가능. 설정 값 없음
- : 범위 지정
, : 여러 값 지정
/ : 초기값, 증가치 설정 시
L : 지정할 수 있는 범위의 마지막 값 설정시 사용. 날짜와 요일에서만,
W : 실행 시점으로부터 가장 가까운 평일
fixedDelay
millisecond 단위로 작업 종료 후 다음 작업 시작까지 지정한 시간이 지난 후 다시 작업 실행.
fixedDelayString으로 문자열로 시간을 표현할 수도 있다.
fixedRate
이전 작업 종료 시점과 연관없이, 작업 시작 시점으로부터 지정 시간 지난 후 다시 작업 실행.
fixedRateString으로 문자열로 시간을 표현할 수 있다.
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import site.soconsocon.socon.store.service.SoconService;
import site.soconsocon.socon.store.service.StoreService;
@Slf4j
@RequiredArgsConstructor
@Component
public class StoreScheduler {
private final StoreService storeService;
// 가게 폐업 상태 업데이트
@Scheduled( cron = "0 0 0 * * *") // 매일 0시에 실행
public void updateCloseStore() {
log.info("가게 상태 업데이트");
storeService.updateCloseStore();
}
}