스케줄링이란 일정한 시간마다 특정한 업무를 수행하는 것이다. 오라클데이터베이스 같은 경우에는 dbms_job에서 지원하며 자바기반 환경에서는 quartz 를 많이 사용한다. 이번 예제에서는 Spring Framework3.,2와 quartz 1.8.6에서 간단히 스케줄링을 구현했다
:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" />
아래에서 태스크는 JOB에 기술되어 실행되는 일이다. JOB에 등록되는 것인데 헷갈리지 말자.
PSJ
Spring Framework3.2에서 아직 Quartz2.0 이상은 지원하지 않는 것 같다. 다음 같은 오류 발생!!
class org.springframework.scheduling.quartz.JobDetailBean has interface org.quartz.JobDetail as super class
따라하기
1. 간단히 스프링 프로젝트 하나 생성하자.
2. pom.xml
<project xmlns="http://maven.apache.org/POM/4.0.0"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.springframework.samples</groupId>
<artifactId>springquarts</artifactId>
<version>0.0.1-SNAPSHOT</version>
<properties>
<!-- Generic properties -->
<java.version>1.7</java.version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<!-- Spring -->
<spring-framework.version>3.2.3.RELEASE</spring-framework.version>
<!-- Hibernate / JPA -->
<hibernate.version>4.2.1.Final</hibernate.version>
<!-- Logging -->
<logback.version>1.0.13</logback.version>
<slf4j.version>1.7.5</slf4j.version>
<!-- Test -->
<junit.version>4.11</junit.version>
</properties>
<dependencies>
<!-- QuartzJobBean in spring-context-support.jar -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context-support</artifactId>
<version>${spring-framework.version}</version>
</dependency>
<!-- Spring and Transactions -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>${spring-framework.version}</version>
</dependency>
<!-- spring quarts에서 transaction이 필요 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
<version>${spring-framework.version}</version>
</dependency>
<!-- Quartz framework -->
<dependency>
<groupId>org.quartz-scheduler</groupId>
<artifactId>quartz</artifactId>
<version>2.1.7</version>
</dependency>
<!-- Logging with SLF4J & LogBack -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>${slf4j.version}</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>${logback.version}</version>
<scope>runtime</scope>
</dependency>
<!-- Hibernate -->
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-entitymanager</artifactId>
<version>${hibernate.version}</version>
</dependency>
<!-- Test Artifacts -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>${spring-framework.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>${junit.version}</version>
<scope>test</scope>
</dependency>
</dependencies>
</project>
3. 이번에는 실제 스케줄링 되면서 실행될 클래스 태스크 클래스와 실행메소드를 만들자.
package jobschedule.edu.onj;
/*
* 스케줄러에 걸어서 실행시킬 JOB
* 본 예제에서는 1초에 한번씩 실행됨
*/
public class RunTask {
public void myWork() {
System.out.println("오라클자바커뮤니티 스프링 스케줄러");
}
}
4. 쿼츠에서 실행될 JOB을 정의하자.(JOB에 TASK를 정의한다.)
두가지 방법이 있는데,,, (본 예제에서는 두 방법 모두 기술하여 테스트)
- MethodInvokingJobDetailFactoryBean을 이용하는 간단방법
<bean id="onjJob"
class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean">
<property name="targetObject" ref="runTask" />
<property name="targetMethod" value="mywork" />
</bean>
- QuartzJobBean을 상속한 클래스를 만들고 XML에서 쿼츠 JOB을 정의하는 방법
package jobschedule.edu.onj;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.springframework.scheduling.quartz.QuartzJobBean;
//QuartzJobBean은 복잡한 스케줄링에 적합한 유연한 스케줄러.
//상속받아서 스케줄러를 구현하자.
public class QuartzJob extends QuartzJobBean {
//실제 실행될 태스크
private RunTask runTask;
//실제 실행될 태스크를 setter 주입 받는다.
public void setRunTask(RunTask runTask) {
this.runTask = runTask;
}
//실행을 원하는 메소드를 CALL한다.
protected void executeInternal(JobExecutionContext context) throwsJobExecutionException {
runTask.myWork();
}
}
XML에서 다음과 같이 정의하면 된다.(XML은 아래에서 한번에 정리)
<!-- 실제스케줄링될 태스크(세터주입될)와 JOB을정의한 클래스등록 -->
<bean name="onjJob"class="org.springframework.scheduling.quartz.JobDetailBean">
<!-- JOB을 정의 -->
<property name="jobClass"value="jobschedule.edu.onj.QuartzJob" />
<!-- 실제스케줄링될 JOB-->
<property name="jobDataAsMap">
<map>
<entry key="runTask" value-ref="runTask" />
</map>
</property>
</bean>
5. Trigger 기술(정의한 JOB을 어떤 주기로 실행할 것인지 정의)
이 또한 두 가지 방법이 있는데 SimpleTrigger와 cronTrigger가 있다. SimpleTrigger는 작업의 주기를 repeatInterval 속성으로 정의하는 반면 cronTrigger는 Unix의 CronTab 설정하듯이 한다.
- SimpleTrigger
<!-- Simple Trigger, run every 1 seconds -->
<bean id="onjTrigger"
class="org.springframework.scheduling.quartz.SimpleTriggerBean">
<!-- 실행할 JOB -->
<property name="jobDetail" ref="onjJob" />
<!-- 1초에 한번씩 -->
<property name="repeatInterval" value="1000" />
<!-- 최초 시작시 1초후에 start -->
<property name="startDelay" value="1000" />
</bean>
- cronTrigger
<!-- 유닉스의 cron tab처럼 설정, 1초마다 -->
<bean id="cronTrigger"
class="org.springframework.scheduling.quartz.CronTriggerBean">
<property name="jobDetail" ref="onjJob" />
<property name="cron__EXPRESSION__" value="0/1 * * * * ?" />
</bean>
6. 스케줄러 관리를 위한 Scheduler Factory를 정의
<!-- job 과 trigger 함께 기술 -->
<beanclass="org.springframework.scheduling.quartz.SchedulerFactoryBean">
<property name="jobDetails">
<list>
<ref bean="onjJob" />
</list>
</property>
<property name="triggers">
<list>
<ref bean="cronTrigger" /> <!-- cronTrigger로바꿔보라 -->
</list>
</property>
</bean>
7. 완성된 XML(springquartz.xml)
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.2.xsd">
<!-- 실제 실행 될 태스크 -->
<bean id="runTask" class="jobschedule.edu.onj.RunTask" />
<!-- 실제스케줄링될 태스크(세터주입될)와 JOB을정의한 클래스등록 -->
<bean name="onjJob"class="org.springframework.scheduling.quartz.JobDetailBean">
<!-- JOB을 정의 -->
<property name="jobClass"value="jobschedule.edu.onj.QuartzJob" />
<!-- 실제스케줄링될 JOB-->
<property name="jobDataAsMap">
<map>
<entry key="runTask" value-ref="runTask" />
</map>
</property>
</bean>
<!--
위에서 정의한 JobDetailBean을 이용하여 스케줄링되는 JOB을 등록하는 방법이외,JOB을 등록하는 다른 방법
MethodInvokingJobDetailFactoryBean을 이용하는 간단한 방법, 스케줄링될클래스와 메소드 정의
<bean id="onjJob"
class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean">
<property name="targetObject" ref="runTask" />
<property name="targetMethod" value="mywork" />
</bean>
-->
<!-- Simple Trigger, run every 1 seconds -->
<bean id="onjTrigger"
class="org.springframework.scheduling.quartz.SimpleTriggerBean">
<!-- 실행할 JOB -->
<property name="jobDetail" ref="onjJob" />
<!-- 1초에 한번씩 -->
<property name="repeatInterval" value="1000" />
<!-- 최초 시작시 1초후에 start -->
<property name="startDelay" value="1000" />
</bean>
<!-- 유닉스의 cron tab처럼 설정, 1초마다 -->
<bean id="cronTrigger"
class="org.springframework.scheduling.quartz.CronTriggerBean">
<property name="jobDetail" ref="onjJob" />
<property name="cron__EXPRESSION__" value="0/1 * * * * ?" />
</bean>
<!-- job 과 trigger 함께 기술 -->
<beanclass="org.springframework.scheduling.quartz.SchedulerFactoryBean">
<property name="jobDetails">
<list>
<ref bean="onjJob" />
</list>
</property>
<property name="triggers">
<list>
<ref bean="cronTrigger" /> <!-- cronTrigger로바꿔보라 -->
</list>
</property>
</bean>
</beans>
8. TEST를 위한 Client Program
package jobschedule.edu.onj;
importorg.springframework.context.support.ClassPathXmlApplicationContext;
public class ScheuleMain {
public static void main(String[] args) {
new ClassPathXmlApplicationContext("springquartz.xml");
}
}
9. 결과
15:19:47.953 [main] INFO org.quartz.core.QuartzScheduler - Scheduler org.springframework.scheduling.quartz.SchedulerFactoryBean#0_$_NON_CLUSTERED started.
15:19:48.718 [org.springframework.scheduling.quartz.SchedulerFactoryBean#0_Worker-1] DEBUG org.quartz.core.JobRunShell - Calling execute on job DEFAULT.onjJob
오라클자바커뮤니티 스프링 스케줄러
15:19:48.937 [Timer-0] DEBUG org.quartz.utils.UpdateChecker - Checking for available updated version of Quartz...
15:19:49.718 [org.springframework.scheduling.quartz.SchedulerFactoryBean#0_Worker-2] DEBUG org.quartz.core.JobRunShell - Calling execute on job DEFAULT.onjJob
오라클자바커뮤니티 스프링 스케줄러
15:19:50.718 [org.springframework.scheduling.quartz.SchedulerFactoryBean#0_Worker-3] DEBUG org.quartz.core.JobRunShell - Calling execute on job DEFAULT.onjJob
오라클자바커뮤니티 스프링 스케줄러
15:19:51.718 [org.springframework.scheduling.quartz.SchedulerFactoryBean#0_Worker-4] DEBUG org.quartz.core.JobRunShell - Calling execute on job DEFAULT.onjJob
오라클자바커뮤니티 스프링 스케줄러
15:19:52.718 [org.springframework.scheduling.quartz.SchedulerFactoryBean#0_Worker-5] DEBUG org.quartz.core.JobRunShell - Calling execute on job DEFAULT.onjJob
오라클자바커뮤니티 스프링 스케줄러
15:19:53.718 [org.springframework.scheduling.quartz.SchedulerFactoryBean#0_Worker-6] DEBUG org.quartz.core.JobRunShell - Calling execute on job DEFAULT.onjJob
오라클자바커뮤니티 스프링 스케줄러
15:19:54.718 [org.springframework.scheduling.quartz.SchedulerFactoryBean#0_Worker-7] DEBUG org.quartz.core.JobRunShell - Calling execute on job DEFAULT.onjJob