[Quartz] SpringBoot 에서 동적으로 properties 파일 읽어 Cron 설정 변경
SpringBoot 환경에서 스케쥴링을 설정하는 방법은 쉽다.
메인 함수 위에 @EnableScheduling 어노테이션을 달고
스케쥴링을 설정할 함수 위에
@Scheduled(fixedDelayString ="600000") //600000은 ms 단위로 = 10분
혹은
@Scheduled(cron = "*/10 * * * * *") // Cron 표현식, 10초에 1번 실행
어노테이션을 달아주기만 하면 된다.
하지만 나는 Cron 표현식을 변경하여 설정해놓은 properties 파일을 변경하면
프로그램을 재시작하지 않아도 자동으로 적용되는 프로그램을 만들고 싶었다.
여기서 사용하게 된 것이
commons-configuration2 와
spring-boot-starter-quartz 이다.
commons-configuration2 는 주기적으로 파일을 읽어와서 편하게 값을 불러올 수 있다.
(commons-configuration2 2.3, commons-beanutils 1.9.3을 사용했다.
** application.properties (10초에 한 번 씩 실행)
cron.test=0/10 * * * * ?
** 파일에서 주기적으로 정보를 읽는 클래스
@Component
public class ReloadBatchConfig {
private ReloadingFileBasedConfigurationBuilder<>PropertiesConfiguration> builder;
@PostConstruct // 초기화가 끝난 후 자동 실행
void init() {
builder = new
ReloadingFileBasedConfigurationBuilder<>(PropertiesConfiguration.class)
.configure(new Parameters().fileBased().setFile(new File("./application.properties")));
// 설정 파일 위치를 적어준다.
PeriodicReloadingTrigger configReloadingTrigger = new PeriodicReloadingTrigger(
builder.getReloadingController(), null, 1, TimeUnit.SECONDS);
//정보를 파일에서 리로드할 시간 설정
configReloadingTrigger.start();
}
public Configuration getCompositeConfiguration() {
try {
return builder.getConfiguration(); //정보 읽음
} catch (ConfigurationException e) {
e.printStackTrace();
}
return null;
}
}
** 변경할 cron 표현식에 따라 주기적으로 실행할 메소드 (@Scheduled로 실행하는 메소드와 동일)
public class TestJob implements Job { // org.quartz.Job을 implements
@Override
public void execute(JobExecutionContext context) throws JobExecutionException {
//실행할 코드
}
}
** 파일에서 읽어온 표현식으로 메소드 실행주기를 바꿔주는 클래스
@Component
@PropertySource("file:./config/batch.properties")
public class SchedulerManager {
private static final Logger logger = LoggerFactory.getLogger(SchedulerManager.class);
private SchedulerFactory schedulerFactory;
public static Scheduler scheduler;
@Autowired
private ReloadBatchConfig reloadConf;
@Value("${cron.test}")
private String testTime; //초기 실행 값 설정
public static String TestTime; //Cron 입력 시 Static만 가능
@PostConstruct
public void init() {
TestTime = testTime;
//초기 실행할 스케줄러의 Trigger 생성
testTrigger = TriggerBuilder.newTrigger().withIdentity("testTriggerKey").
withIdentity(new TriggerKey("testTriggerKey")).
withSchedule(CronScheduleBuilder.cronSchedule(TestTime)).build();
try {
start();
} catch (SchedulerException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public void start() throws SchedulerException{
schedulerFactory = new StdSchedulerFactory();
//여러 job을 실행 시 Scheduler도 따로 생성해준다.
testScheduler = schedulerFactory.getScheduler();
testScheduler.start();
//실행할 Job
JobDetail testJob = JobBuilder.newJob(TestJob.class).build();
//실행
testScheduler.scheduleJob(testJob, testTrigger);
}
//10초마다 batch.properties 읽어와서 배치 설정 바꿈
@Scheduled(fixedDelayString = "10000")
public void get(){
public static String newTestTime = reloadConf.getCompositeConfiguration().getString("cron.test");
try {
//파일의 값이 변경되었을 때만 수행
if (testcheduler != null && !testTime.equals(newTestTime)) {
//변경될 cron 표현식을 쓸 새로운 Trigger 생성
CronTriggerImpl newTestTrigger = (CronTriggerImpl) testScheduler.getTrigger(testTrigger.getKey());
newReportTrigger.setCronExpression(newTestTime); //Trigger 값 변경
reportScheduler.rescheduleJob(testTrigger.getKey(), newTestTrigger); //주기 변경, 메소드 재실행된다.
reportTime = newReportTime; //값 비교를 위한 초기화
}
} catch (Exception e) {
// TODO Auto-generated catch block
logger.error("[Exception] Cron : " + e.getMessage());
}
}
}
프로그램 실행 중에 외부에 있는 application.properties 파일의 값을 변경하면
변경한 cron 표현식의 주기대로 메소드가 실행된다.