Framework/Spring

[Quartz] SpringBoot 에서 동적으로 properties 파일 읽어 Cron 설정 변경

콩이볼 2019. 5. 21. 16:40

 

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 표현식의 주기대로 메소드가 실행된다.