본문 바로가기

Spring

[Spring Boot] Quartz - RAM Job Store 예제

Quartz JobStore에는

RAM JobStore : Scheduler Data를 메모리에 저장

JDBC JobStore : Scheduler Data를 DB에 저장

가 있다.

 

오늘은 Scheduler Data를 메모리에 저장하는 RAM JobStore를 Spring Boot로 구현해본다.

소스코드 : github.com/Gupuroom/QuartzRamJobStore.git

 

개발환경

Eclipse 2020-09 - 필수

SpringBoot - 필수

Gradle - 필수

Lombok - 필수

Quartz - 필수

1. build.gradle 의존성 추가.

implementation 'org.springframework.boot:spring-boot-starter-quartz'

2. Quartz 관련 설정

Quartz관련 설정은 application.yml javaConfig 있다. 예시에서는 application.yml 사용한다.

spring:
  quartz:
    wait-for-jobs-to-complete-on-shutdown: true
    properties:
     org:
      quartz:
       scheduler:
         skipUpdateCheck: true
       threadPool:
         class: org.quartz.simpl.SimpleThreadPool
         threadCount: 5
       jobStore:
         class: org.quartz.simpl.RAMJobStore
       plugin:
         shutdownhook:
           class: org.quartz.plugins.management.ShutdownHookPlugin
           cleanShutdown: true\

3. Job 

  • Trigger가 발생했을 때 실질적으로 동작할 내용을 정의한다.
  • Trigger발생시 스케줄러는 JobExecutionContext 객체를 넘겨주고 execute()를 호출해 Job에 정의되어 있는 내용을 실행시킨다.
  • JobExecutionContext는 Scheduler, Trigger, JobDetail등을 포함하여 Job인스턴스에 대한 정보를 저장해논 객체다.
  • Spring, SpringBoot에서는 executeInternal()을 사용한다. (Spring에서 execute()인터페이스를 정의해논 QuartzJobBean 객체를 지원하기 때문이다.

CronJob

public class CronJob extends QuartzJobBean {
	private int MAX_SLEEP_IN_SECONDS = 5;

	@Override
	protected void executeInternal(JobExecutionContext context) throws JobExecutionException {
		JobDataMap jobDataMap = context.getJobDetail().getJobDataMap();
		String Dev = jobDataMap.getString("Dev");
		String Company = jobDataMap.getString("Company");
		JobKey jobKey = context.getJobDetail().getKey();

		log.info("============================================================================");
		log.info("Develope by {} from {}", Dev, Company);
		log.info("CronJob started :: sleep : {} jobKey : {}", MAX_SLEEP_IN_SECONDS, jobKey);

		IntStream.range(0, 4).forEach(i -> {
			log.info("CronJob Counting - {}", i);
			try {
				TimeUnit.SECONDS.sleep(MAX_SLEEP_IN_SECONDS);
			} catch (InterruptedException e) {
				log.error(e.getMessage(), e);
			}
		});
		log.info("CronJob ended :: jobKey : {}", jobKey);
		log.info("============================================================================");
	}
}

: context에서 jobDataMap 객체를 가져와 log 호출하는 Job.class이다.

4. JobDetail

  • Job을 실행시키기 위한 정보를 담고 있는 객체다.
  • Job의 이름, 그룹, JobDataMap 속성 등을 지정할 수 있다.
  • Trigger가 Job을 수행할 때 이 정보를 기반으로 스케줄링 한다.
	@Bean
	public JobDetail scheduleJobDetail()
	{
		JobDataMap jobMap = new JobDataMap();
		jobMap.put("Dev", "이동재");
		jobMap.put("Company", "*****");
		return JobBuilder
			.newJob(CronJob.class).withIdentity("scheduleJob").usingJobData(jobMap).storeDurably()
			.build();
		
//		return JobBuilder
//			.newJob(CronJob.class).withIdentity("scheduleJob").usingJobData("name","이동재").storeDurably()
//			.build();
	}

scheduleJobDetail()에서는 

  • JobBuilder를 통해서 JobDetail을 생성한 후에 반환한다.
  • .newJob은 JobDetail을 가진 Trigger가 호출 되었을 때 실행시킬 클래스를 지정해놓은 것이다. 
  • scheduleJobDetail을 가지고 있는 Trigger가 호출되어 실행되면 3.Job에서 소개한 CronJob이 호출된다. 

5. JobDataMap

  • JobDataMap은 Job 인스턴스가 실행될 때 사용할 수 있는 정보를 담은 객체다.
  • JobDetail을 생성할 때 JobDataMap도 같이 설정한다.
	@Bean
	public JobDetail scheduleJobDetail()
	{
		JobDataMap jobMap = new JobDataMap();
		jobMap.put("Dev", "이동재");
		jobMap.put("Company", "*****");
		return JobBuilder
			.newJob(CronJob.class).withIdentity("scheduleJob").usingJobData(jobMap).storeDurably()
			.build();
		
//		return JobBuilder
//			.newJob(CronJob.class).withIdentity("scheduleJob").usingJobData("name","이동재").storeDurably()
//			.build();
	}

- [주석] JobBuilder.usingJobData 사용하여 JobDataMap 설정해 있다.

- [“key”,”value”]형식으로 지정하고 Job.class에서  key값으로 value 가져와 사용한다.

- 여러 개의 Data 담고 싶을 경우JobDataMap 객체를 만들어서 사용한다.

 

- JobDataMap에서 설정한 값들은 CronJob.class에서 key값으로 가져올 수 있다. 활용예시는 아래에서 다룬다.

활용 예시

CronJob.java

public class CronJob extends QuartzJobBean {

	@Override
	protected void executeInternal(JobExecutionContext context) throws JobExecutionException {
		JobDataMap jobDataMap = context.getJobDetail().getJobDataMap();
		String Dev = jobDataMap.getString("Dev");
		String Company = jobDataMap.getString("Company");
		JobKey jobKey = context.getJobDetail().getKey();

		log.info("============================================================================");
		log.info("Develope by {} from {}", Dev, Company);
		log.info("CronJob started :: jobKey : {}", jobKey);
	}
}

- [5행] context객체를 통해 JobDataMap 가져온다.

- [6행,7행] JobDetail에서 설정한 Key값으로 Dev Company value 가져와 log 화면에 출력한다.

- log로 출력해서 제대로 출력되는지 확인한다. ( 혹시 log가 안된다면 System.out.println()으로 확인해도 된다. )

6. Trigger

  • Trigger Scheduler Job 실행시킬 조건(ex.반복 횟수, 시작시간)등을 설정한다.
  • Scheduler 해당 정보를 기반으로 Job 수행한다.

scheduleJobTrigger

@Bean
	public Trigger scheduleJobTrigger()
	{
		//cron
		CronScheduleBuilder cronBuilder = CronScheduleBuilder.cronSchedule("0/20 * * * * ?");
		
		return TriggerBuilder
				.newTrigger().forJob(scheduleJobDetail()).withIdentity("scheduleTrigger").withSchedule(cronBuilder)
				.build();
	}
  • CronScheduleBuilder를 사용해 반복 및 시작 조건을 설정한다.
  • TriggerBuilder를 통해 JobDetailcronBuilder를 설정한다.

참고

'Spring' 카테고리의 다른 글

[Spring boot] Form 서버 연동 시 에러 발생 해결  (0) 2021.07.28