스프링부트 스케줄러 동적 처리

2022. 9. 26. 11:26스프링

@Slf4j
@Component
public class DynamicChangeScheduler {
    private ThreadPoolTaskScheduler scheduler;
    private String cron;
    private AnnualFeeService annualFeeService;
    // 생성자 주입을 통해 db의  자동갱신 기준일 cron 값 가져옴
    public DynamicChangeScheduler(AnnualFeeService annualFeeService) {
        this.annualFeeService = annualFeeService;
        List<AnnualFee> list = annualFeeService.list();
        cron = list.get(0).getCron();
    }
    // 스케줄러 시작
    public void startScheduler() {
        scheduler = new ThreadPoolTaskScheduler();
        scheduler.initialize();
        // scheduler setting
        scheduler.schedule(getRunnable(), getTrigger());
    }
    // cron 값 setter
    public void changeCronSet(String cron) {
        this.cron = cron;
    }
    // 스케줄러 종료
    public void stopScheduler() {
        scheduler.shutdown();
    }
    // 실제 할 일을 실행할 메소드
    private Runnable getRunnable() {
        return () -> annualFeeService.call();
    }
    // cron setting
    private Trigger getTrigger() {
        return new CronTrigger(cron);
    }
    // was를 실행할 때
    @PostConstruct
    public void init() {
        startScheduler();
    }
    // 종료
    @PreDestroy
    public void destroy() {
        stopScheduler();
    }




}

스프링부트에 @Scheduled 애너테이션 사용하면 쉽지만 동적 제어를 하기 위해서는 저렇게 사용이 불가하다.

@Scheduled 또한 yml파일에 있는 정보를 가져와서 사용할 수 있지만 사용자 페이지에서 직접 cron 표현식을 변경하기 위해서는 이 방법을 사용해야 한다. db에 있는 cron 셋팅값을 가져와서 cron 필드를 초기화 시켜주고 변경이 필요한 시점에

사용할 class에서 DynamicChangeScheuler를 주입받은 후에 

 

dynamicChangeScheduler.stopScheduler();
        try {
            // 쓰레드 대기 상태
            Thread.sleep(1000);
            // cron 값 변경
//            dynamicChangeScheduler.changeCronSet("* * * * * *");
            dynamicChangeScheduler.changeCronSet(dynamic);
            dynamicChangeScheduler.startScheduler();
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }

이런 식으로 사용하면 된다.

 

주의 할 점은 트랜잭션 처리를 위해 

해야 할 일을 직접 getRunnable() 메소드에 넣지 말고 따로 다른 곳에서 트랜잭션 처리 후 호출한다. 

private Runnable getRunnable() {
    return () -> annualFeeService.call();
}
@Transactional
public void call() {