Quartz Job 스케줄러를 사용하기 위해서 POM에 다음을 추가합니다.
pom.xml
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-quartz</artifactId> </dependency>
Quartz의 환경설정 파일을 작성합니다. 다음의 예제에서는 RAM Job Store를 사용하였으나 Quartz Job이 영속적으로 동작하기 위해서는 JDBC Job Store를 사용할 수 있으며 이 경우 다음을 수정해야 합니다.
src/main/resources/quartz.properties
# thread-pool org.quartz.threadPool.class=org.quartz.simpl.SimpleThreadPool org.quartz.threadPool.threadCount=80 org.quartz.threadPool.threadsInheritContextClassLoaderOfInitializingThread=true # job-store org.quartz.jobStore.class=org.quartz.simpl.RAMJobStore # others org.quartz.jobStore.misfireThreshold = 60000
Quartz Starter를 추가했으므로 Spring Boot는 자동으로 Quartz를 실행시킬 것이나, 커스터마이징을 위해서 다음과 같이 Quartz Auto Configuration을 exclude시킵니다.
src/main/resources/application.yml
spring: ################# ## Auto Configure ################# autoconfigure: exclude: - org.springframework.boot.autoconfigure.quartz.QuartzAutoConfiguration
Quartz Job에서 Autowire를 사용할 수 있도록 다음의 클래스를 작성합니다.
import org.quartz.spi.TriggerFiredBundle; import org.springframework.beans.BeansException; import org.springframework.beans.factory.config.AutowireCapableBeanFactory; import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContextAware; import org.springframework.scheduling.quartz.SpringBeanJobFactory; public final class AutoWiringSpringBeanJobFactory extends SpringBeanJobFactory implements ApplicationContextAware { private transient AutowireCapableBeanFactory beanFactory; public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { beanFactory = applicationContext.getAutowireCapableBeanFactory(); } @Override protected Object createJobInstance(final TriggerFiredBundle bundle) throws Exception { final Object job = super.createJobInstance(bundle); beanFactory.autowireBean(job); return job; } }
이제 Boot Configuration을 작성합니다.
import lombok.extern.slf4j.Slf4j; import org.quartz.JobDetail; import org.quartz.Trigger; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.ApplicationContext; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.core.io.ClassPathResource; import org.springframework.scheduling.quartz.SchedulerFactoryBean; import org.springframework.scheduling.quartz.SpringBeanJobFactory; @Configuration @Slf4j public class QuartzConfiguration { @Autowired ApplicationContext applicationContext; @Bean public SchedulerFactoryBean scheduler() { SchedulerFactoryBean schedulerFactory = new SchedulerFactoryBean(); schedulerFactory.setConfigLocation(new ClassPathResource("quartz.properties")); schedulerFactory.setJobFactory(springBeanJobFactory()); return schedulerFactory; } @Bean public SpringBeanJobFactory springBeanJobFactory() { AutoWiringSpringBeanJobFactory jobFactory = new AutoWiringSpringBeanJobFactory(); jobFactory.setApplicationContext(applicationContext); return jobFactory; } }
배치 작업을 위해서 Migration Job을 하나 생성합니다.
import lombok.extern.slf4j.Slf4j; import org.quartz.Job; import org.quartz.JobExecutionContext; import org.quartz.JobExecutionException; import org.springframework.stereotype.Component; import java.util.List; @Component @Slf4j public class MigrationJob implements Job { @Override public void execute(JobExecutionContext context) throws JobExecutionException { } }
이제 Quartz Configuration에 Job을 등록시킵니다.
import io.datadynamics.projects.migrator.jobs.MigrationJob; import lombok.extern.slf4j.Slf4j; import org.quartz.JobDetail; import org.quartz.SimpleTrigger; import org.quartz.Trigger; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.ApplicationContext; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.core.io.ClassPathResource; import org.springframework.scheduling.quartz.JobDetailFactoryBean; import org.springframework.scheduling.quartz.SchedulerFactoryBean; import org.springframework.scheduling.quartz.SimpleTriggerFactoryBean; import org.springframework.scheduling.quartz.SpringBeanJobFactory; @Configuration @Slf4j public class QuartzConfiguration { @Autowired ApplicationContext applicationContext; @Bean public SchedulerFactoryBean scheduler(Trigger trigger, JobDetail job) { SchedulerFactoryBean schedulerFactory = new SchedulerFactoryBean(); schedulerFactory.setConfigLocation(new ClassPathResource("quartz.properties")); schedulerFactory.setJobFactory(springBeanJobFactory()); schedulerFactory.setJobDetails(job); schedulerFactory.setTriggers(trigger); return schedulerFactory; } @Bean public SpringBeanJobFactory springBeanJobFactory() { AutoWiringSpringBeanJobFactory jobFactory = new AutoWiringSpringBeanJobFactory(); jobFactory.setApplicationContext(applicationContext); return jobFactory; } @Bean public JobDetailFactoryBean jobDetail() { JobDetailFactoryBean jobDetailFactory = new JobDetailFactoryBean(); jobDetailFactory.setJobClass(MigrationJob.class); jobDetailFactory.setName("Migration Job"); jobDetailFactory.setDescription("Invoke Migration Job service..."); jobDetailFactory.setDurability(true); return jobDetailFactory; } @Bean public SimpleTriggerFactoryBean trigger(JobDetail job) { SimpleTriggerFactoryBean trigger = new SimpleTriggerFactoryBean(); trigger.setJobDetail(job); int frequencyInSec = 1; log.info("Configuring trigger to fire every {} seconds", frequencyInSec); trigger.setRepeatInterval(frequencyInSec * 6000); trigger.setRepeatCount(SimpleTrigger.REPEAT_INDEFINITELY); trigger.setName("Mail Sending Trigger"); return trigger; } }
Spring Scheduling에 대해서 상세하게 알고 싶은 경우 https://www.baeldung.com/spring-quartz-schedule 을 참고하십시오.