2013년 11월 12일 화요일

[SPRING Framework강좌, Spring학원]스프링3.2, 쿼츠1.8.6 스케줄링

[SPRING Framework강좌, Spring학원]스프링3.2, 쿼츠1.8.6 스케줄링(SpringFramework3.2, Quartz 1.8.6 Job Schedule)
 
 
스케줄링이란 일정한 시간마다 특정한 업무를 수행하는 것이다. 오라클데이터베이스 같은 경우에는 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) throws JobExecutionException {
             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 함께 기술 -->
       <bean class="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 함께 기술 -->
       <bean class="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;
 
import org.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

댓글 없음:

댓글 쓰기