The error I get is as follows:

SEVERE: StandardWrapper.Throwable
org.springframework.beans.factory.CannotLoadBeanClassException: Error loading class [org.springframework.scheduling.quartz.JobDetailBean] for bean with name ‘runMeJob’ defined in ServletContext resource [/WEB-INF/quartz-servlet.xml]: problem with class file or dependent class; nested exception is java.lang.IncompatibleClassChangeError: class org.springframework.scheduling.quartz.JobDetailBean has interface org.quartz.JobDetail as super class

 

이런 오류 메시지가 나올때는

 

quartz 다운로드 페이지에서 Quartz 1.8.6 버전으로 lib 교체해주면 된다.



출처 - http://jhroom.tistory.com/129



===================================================================================


WAS를 이용해서 주기적으로 특정 프로그램 실행하는 방법이 spring에서는 2가지가 있다. (뭐 더 있을수도 있다 -_-)

하나는 spring batch이고 다른 하나는 quartz를 이용하는 방법이다.

뭐가좋은지는 나도 잘 모른다. 일단 quartz가 어떤식으로 동작하는지 먼저 공부했으므로 이것부터 글 적는다.

 

1. 샘플 프로젝트 생성

STS 에서 [File] - [New] - [Spring Template Project] 메뉴를 클릭한 후 Spring MVC Project를 이용해 샘플 프로젝트를 생성한다.

 

2. pom.xml 파일 수정

quartz 관련 모듈을 이용하기 위해서 pom.xml 파일에 관련 라이브러리들 넣는다.

spring-tx, quartz, commons-collections, javax.transaction 4개 넣어줘야한다.

<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-tx</artifactId>
    <version>${org.springframework-version}</version>
</dependency>
<!-- Quartz framework and dependencies -->
<dependency>
    <groupId>opensymphony</groupId>
    <artifactId>quartz</artifactId>
    <version>1.6.3</version>
    <scope>compile</scope>
</dependency>
<!-- Quartz 1.6.0 depends on commons collections -->
<dependency>
    <groupId>commons-collections</groupId>
    <artifactId>commons-collections</artifactId>
    <version>3.1</version>
    <scope>runtime</scope>
</dependency>
<!-- Quartz 1.6.0 requires JTA in non J2EE environments -->
<dependency>
    <groupId>javax.transaction</groupId>
    <artifactId>jta</artifactId>
    <version>1.1</version>
    <scope>runtime</scope>
</dependency>

 

3. 주기적으로 실행 될 Bean 생성

2개의 Bean을 만든다.

CronQuartz1.java

package com.mungchung.sample;
 
import java.text.SimpleDateFormat;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.springframework.scheduling.quartz.QuartzJobBean;
 
public class CronQuartz1 extends QuartzJobBean{
    @Override
    protected void executeInternal(JobExecutionContext arg0)
            throws JobExecutionException {
        long time = System.currentTimeMillis();
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy.MM.dd HH:mm:ss");
        System.out.println("Cron trigger 1 (5 second): current time = " + sdf.format(time));
    }
 
}

CronQuartz2.java

package com.mungchung.sample;
 
import java.text.SimpleDateFormat;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.springframework.scheduling.quartz.QuartzJobBean;
 
public class CronQuartz2 extends QuartzJobBean{
    @Override
    protected void executeInternal(JobExecutionContext arg0)
            throws JobExecutionException {
        long time = System.currentTimeMillis();
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy.MM.dd HH:mm:ss");
        System.out.println("Cron trigger 2 (1 minute): current time = " + sdf.format(time));
    }
}

 

4. quartz Bean과 위에서 생성한 Bean 연동

2개의 Bean이 각각 다른 시간차이로 실행되도록 설정해줄것이다.

CronQuartz1.java - 5초마다 실행

CronQuartz2.java - 1분마다 실행

 

/src/main/webapp/WEB-INF/spring/root-context.xml

<!-- 1. Cron 대상이 되는 클래스 정의 -->
<bean id="cronQuartz1" class="org.springframework.scheduling.quartz.JobDetailBean">
    <property name="jobClass" value="com.mungchung.sample.CronQuartz1"/>
</bean>
<bean id="cronQuartz2" class="org.springframework.scheduling.quartz.JobDetailBean">
    <property name="jobClass" value="com.mungchung.sample.CronQuartz2"/>
</bean>
 
<!-- 2. Cron 시간 설정 -->
<bean id="cronTrigger1" class="org.springframework.scheduling.quartz.CronTriggerBean">
    <property name="jobDetail" ref="cronQuartz1"/>
    <property name="cronExpression" value="0/5 * * * * ?"/>
</bean>
<bean id="cronTrigger2" class="org.springframework.scheduling.quartz.CronTriggerBean">
    <property name="jobDetail" ref="cronQuartz2"/>
    <property name="cronExpression" value="0 0/1 * * * ?"/>
</bean>
 
<!-- 3. Cron 실행 -->
<bean class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
    <property name="triggers">
        <list>
            <ref bean="cronTrigger1"/>
            <ref bean="cronTrigger2"/>
        </list>
    </property>
    <property name="quartzProperties">
        <props>
            <prop key="org.quartz.threadPool.class">org.quartz.simpl.SimpleThreadPool</prop>
            <prop key="org.quartz.threadPool.threadCount">3</prop>
            <prop key="org.quartz.threadPool.threadPriority">4</prop>
            <prop key="org.quartz.jobStore.class">org.quartz.simpl.RAMJobStore</prop>
            <prop key="org.quartz.jobStore.misfireThreshold">60000</prop>
        </props>
    </property>
</bean>

 

 

Cron Expression

총 7개의 필드 있고 마지막 필드(년도)는 생략 가능하다

 필드이름허용 값 
초(Seconds)0 ~ 59 
분(Minutes)0 ~ 59 
시간(Hours)0 ~ 23
달의 날짜(Day-of-month)1 ~ 31
달(Month) 1 ~ 12 or JAN ~ DEC
주의 날짜(Day-of-week)1 ~ 7 or SUN-SAT
년도(Year) (선택가능) 빈값, 1970 ~ 2099

Cron Expression의 특수문자
Expression설명 예시 
    * 모든 수를 나타냄  
     -값의 사이를 의미* 10-13 * * * *     10,11,12,13분에 동작함 
     ,특정값 지칭* 10,11,13 * * * *      10,11,13분에 동작함
     /값의 증가를 표현* 0/5 * * * *       0분부터 시작해서 5분마다 동작 
     ?특별한 값이 없음을 나타냄(day-of-month, day-of-week 필드만 사용) 
     L마지막 날을 나타냄(day-of-month, day-of-week 필드만 사용) 

6. 실행결과

실행결과를 보면 하나는 5초마다, 다른 하나는 1분마다 Bean이 실행되고 있음을 알수 있다.

01.png





===================================================================================


sping mvc template project로 구성 시

quartz-1.8.6과 sprint-tx를 적용하여 문제 없이 구현 하였다.


spring-tx를 pom.xml에 추가 하지 않을 경우 다음과 같이 에러 발생

심각: Exception sending context initialized event to listener instance of class org.springframework.web.context.ContextLoaderListener

org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'schedulerFactory' defined in ServletContext resource [/WEB-INF/applicationContext.xml]: Instantiation of bean failed; nested exception is java.lang.NoClassDefFoundError: org/springframework/transaction/TransactionException


===================================================================================


What Is Quartz

   

원문http://www.onjava.com/lpt/a/6207

저자Chuck Cavaness

2005-09-28

   

Quartz

Quartz는 오픈 소스 작업 스케줄링 프레임워크이다. Quartz는 완전히 자바로 작성되어 있으며, J2SE와 J2EE 어플리케이션 모두에서 사용될 목적으로 설계되었다. Quartz는 매우 유연하며 단순한 구조를 제공한다. 간단한 작업은 물론 복잡한 작업 모두에 대한 스케줄링을 작성할 수 있다. Quartz는 또한 EJB, JavaMail 등을 위한 데이터베이스 지원, 클러스터링, 플러그 인, 미리 내장된 작업들을 포함하고 있으며, cron과 유사한 표현식도 지원한다.

   

매일 또는 매주 오후 11시 30분 또는 매달 말일에만 실행하는 작업을 수행하는 어플리케이션을 작성해 본 적이 있는가? 수작업 없이 자동으로 실행될 수 있는 작업이 실행되는 동안 만약 실행하는 동안 심각한 오류가 발생할 경우, 어플리케이션은 잘못되었다는 것을 스스로 알아내 알려주고 이를 다시 실행시키도록 시도해야 할 것인가? 여러분과 팀이 자바로 프로그램을 작성하고 있는가? 만약 이들 질문들에 대한 대답이 "그렇다"라면, Quartz Scheduler를 사용해 보아라.

   

Job Scheduling Made Easy

Quartz는 오픈 소스 작업 스케줄링 프레임워크로 완전히 자바로 작성되었다. 작업 스케줄링 이라는 용어에 대해 너무 겁먹지 말아라. Quartz 프레임워크는 수많은 기능들이 매우 단순한 형태로 무장되어 있으며, 놀라울 정도로 매우 사용하기 쉽게 되어 있다.

   

org.quartz.Job 인터페이스를 구현하는 자바 클래스를 작성하기만 하면 된다. Job 인터페이스는 다음과 같은 하나의 메소드만을 포함하고 있다.

   

public void execute(JobExecutionContext context) throws JobExecutionException;

   

여러분이 작성한 Job 클래스에서 execute() 메소드에 몇 가지 로직을 추가한다. Job 클래스와 스케줄을 설정하게 되면, Quartz는 그 나머지 작업을 처리해준다. Scheduler가 Job에 알려줄 시간이라고 판단하게 되면, Quartz 프레임워크는 Job 클래스의 execute() 메소드를 실행하여 작업을 수행하도록 만들어준다. Scheduler에 어떠한 것도 보고해줄 필요가 없으며, 어떤 특별한 메소드를 호출할 필요도 없다. 단순히 Job 내에 있는 작업들만 수행해주면 끝이다. 만약 여러분이 이후에 다시 Job이 호출되도록 설정했다면, Quartz 프레임워크는 적절한 때에 다시 이를 호출하는 부분을 담당해준다.

   

만약 여러분이 Apache Struts와 같은 유명한 오픈 소스 프레임워크를 써본 경험이 있다면, Quartz의 설계 내용과 컴포넌트에도 쉽게 익숙해질 것이다. 비록 이 두 오픈 소스 프로젝트가 전혀 서로 다른 문제점들을 해결해주고 있지만, 오픈 소스 소프트웨어를 항시 사용하는 사람들이라면 편안한 느낌을 받을 것이다. Quartz는 표준 독립형 J2SE 어플리케이션 내에서라든지, 웹 어플리케이션 내부, 심지어는 J2EE 어플리케이션 서버 내에서 사용될 수 있다.

   

The History behind Quartz

Quartz가 주목을 받기 시작한 것은 올해부터지만, 나온 지는 좀 되었다. Quartz는 James House에 의해 개발되었으며, 원래는2001년 봄에 SourceForge 프로젝트에 추가되었다. 수년이 지나면서 많은 기능들이 추가되어 배포되었지만, 두각을 나타내기 시작하면서 주목을 받기 시작한 것은 OpenSymphony 프로젝트의 일부로 되면서 새로운 사이트로 옮겨지게 된 때부터였다.

   

House는 자신을 도와주는 여러 파트 타임 개발자와 함께 여전히 개발 작업의 많은 부분에 참여하고 있다. Quartz 개발 팀은 올 해 1.5 배포판을 포함해 다양한 새로운 버전들을 배포할 수 있었으며, 이는 현재 candidate 릴리즈 단계에 있다.

   

Getting Your Hands on Quartz

Quartz 프로젝트는 OpenSymphony 사이트에 호스팅 되어 있다. 이 사이트에는 JavaDocs, 튜토리얼, CVS, 사용자와 개발자 포럼 및 다운로드 링크와 같은 여러 유용한 정보들이 제공되고 있다.

   

다운로드 링크에서 배포판을 다운로드 한 후, 적절한 위치에 압축을 푼다. 이 안에 보면 어플리케이션에서 사용할 수 있는 Quartz바이너리 파일이 포함되어 있다. Quartz 프레임워크에서 요구 되는 다른 의존적인 라이브러리는 거의 없다.

   

배포판에 보면, <Quartz 설치 디렉터리>/lib/core와 <Quartz 설치 디렉터리>/lib/optional 디렉터리에 있는 다른 의존 라이브러리들을 프로젝트에 추가하면 된다. 이들 대부분은 표준 Jakarta Commons 라이브러리들로, 여러분도 잘 알고 있는 Commons Logging, Commons BeanUtils 등이다.

   

The quartz.properties File

Quartz에는 quartz.properties라는 환경 설정 파일이 포함되어 있다. 이 파일을 사용하면 Quartz 프레임워크의 런타임 환경을 수정할 수 있다. 디폴트로, Quartz 바이너리 내에 포함되어 있는 파일이 사용된다. 이 파일을 복사하여 클래스들이 있는 디렉터리에 두면 클래스 로더가 이를 참조할 수 있다. 예제 1은 quartz.properties 파일에 대한 간단한 예이다.

   

예제 1. quartz.properties 파일을 통해 Quartz 런타임을 변경할 수 있다.

#===============================================================

# Configure Main Scheduler Properties

#===============================================================

   

org.quartz.scheduler.instanceName = QuartzScheduler

org.quartz.scheduler.instanceId = AUTO

   

#===============================================================

# Configure ThreadPool

#===============================================================

   

org.quartz.threadPool.class = org.quartz.simpl.SimpleThreadPool

org.quartz.threadPool.threadCount = 5

org.quartz.threadPool.threadPriority = 5

   

#===============================================================

# Configure JobStore

#===============================================================

   

org.quartz.jobStore.misfireThreshold = 60000

org.quartz.jobStore.class = org.quartz.simpl.RAMJobStore

   

일단 Quartz 바이너리와 의존 라이브러리들을 프로젝트에 추가했고, quartz.properties 파일을 클래스패스 디렉터리에 추가했다면, 이제 몇몇 Job들을 작성해보자. 그러나, 이 작업을 해보기 전에 Quartz 아키텍처에 관해 간단하게 살펴보도록 하자.

   

Inside the Quartz Architecture

크기로 보자면, Quartz는 다른 대부분의 오픈 소스 프레임워크들과 유사하다. Quartz는 약 300 개의 자바 클래스들과 인터페이스들을 포함하고 있으며, 이들은 약 12개의 패키지로 구성되어 있다. 이는 Apache Struts에 있는 11개의 패키지에 약 325개의 클래스들과 인터페이스들에 비견될 수 있다. 비록 이 크기가 프레임워크의 질을 결정하는데 사용되는 특징이 될 수는 없겠지만, 여기에서 말하고자 하는 점은 Quartz 내에 수많은 기능들이 포함되어 있다는 사실이다. 그리고, 그러한 기능들이 바로 프레임워크의 질을 결정하는데 사용되는 하나의 요소이다. 이는 오픈 소스에만 국한되는 내용은 아니다.

   

The Quartz Scheduler

Quartz 프레임워크의 핵심은 Scheduler 이다. Scheduler는 Quartz 어플리케이션을 위한 런타임 환경을 관리하는 책임을 지니고 있다. Scheduler 그 자체가 모든 작업들 수행하는 것은 아니다. Scheduler는 프레임워크 내부에 있는 매우 중요한 몇몇 컴포넌트들에 그 작업을 의존하고 있다. 확장성을 보장하기 위해, Quartz는 멀티스레드 아키텍처를 기반으로 하고 있다. Quartz 프레임워크가 시작될 때, 프레임워크는 스케줄링 된 Job들을 실행하기 위해 Scheduler가 사용하는 "worker 스레드들"을 초기화 한다. Quartz가 동시에 수많은 Job들을 실행 가능한 이유가 바로 여기에 있다. Quartz는 스레드 환경을 관리하기 위해 ThreadPool관리 컴포넌트들에 의존하고 있는데, 그 결합도는 느슨하다. 이 글을 통해 여러 번 언급할 것이지만, 이는 Quartz에 있는 모든 것들은 환경 설정이 가능하거나 사용자가 정의해 지정할 수 있음을 의미한다. 예를 들면, 여러분이 정의한 "ThreadPool" 관리 기능을 플러그 인 형태로 끼워 넣고 싶은 경우, 이러한 작업이 가능하다.

   

Jobs, Jobs, and More Jobs

Quartz의 용어를 사용하자면, Job은 작업을 수행하는 간단한 자바 클래스이다. 이 작업은 자바에서 코드로 작성 가능한 그 어떠한 것이라도 될 수 있다. 필수적으로 요구되는 사항은, org.quartz.Job 인터페이스를 구현하고, 심각한 오류 발생 시JobExecutionException을 발생시키는 것뿐이다. 여러분은 이미 앞에서 Job 인터페이스와 포함된 execute() 메소드를 보았다.

   

Job 인터페이스와 execute() 메소드를 구현했다면, Quartz는 Job 실행 시기가 되었을 때, Job을 호출한다. execute() 메소드 안에서 무엇을 수행하는가는 전적으로 개발자에게 달려 있다. 다음은 Job 내부에서 실행할 작업들에 대한 몇몇 예이다.

   

● JavaMail이나 Commons Net과 같은 다른 메일 프레임워크를 사용하여 전자메일 전송

● EJB에 대한 원격 인터페이스를 생성한 후, 이 인터페이스의 메소드 호출

● Hibernate 세션을 얻어 관계형 데이터베이스에 있는 데이터 질의와 갱신

● OSWorkflow를 사용하여 Job으로부터 워크플로우 호출

● FTP를 사용해 파일 옮기기

● Ant 빌드 스크립트를 호출해 스케줄링 되어 있는 빌드 작업 시작

   

수많은 여러 작업들이 가능하며, 이것이 바로 Quartz 프레임워크를 매우 강력하게 만들어주는 이유이다. Quartz는 매우 일반적이고 반복적인 스케줄을 작성해주는 메커니즘을 제공하기 때문에, 개발자는 단지 실행을 위해 호출될 자바 클래스들만 작성하면 된다.

   

Job Management and Storage

Job들의 스케줄이 지정되었다면, Scheduler는 이러한 Job들을 기억하고 이들을 실행시킬 시간을 지속적으로 추적해야 한다. 만약 여러분의 Job이 30분 늦게 시작되거나 30초 일찍 시작된다면 Quartz는 그렇게 유용하지 않을 것이다. 사실, 스케줄이 지정된Job들 상에 있는 execute() 메소드를 호출하는 시간은 매우 정확해야 한다. Job 저장과 관리는 Quartz에서 JobStore로 일컬어지는 개념을 통해 이루어진다.

   

Available JobStores

Quartz 프레임워크에서는 두 가지 기본적인 JobStore 타입을 제공한다. Scheculer 정보를 유지하는데 일반적인 메모리(RAM)을 사용하는 첫 번째 타입은 RAMJobStore라 불린다. 이러한 타입의 JobStore는 설정 및 실행이 매우 간단하다. 많은 어플리케이션들에 대해 이러한 JobStore만으로도 충분할 것이다. 그러나, Scheduler 정보가 JVM에 할당되어 있는 메모리에 저장되기 때문에, 어플리케이션이 멈추게 되면, 스케줄과 관련된 모든 정보가 사라진다. 만약 어플리케이션이 재 시작하는 경우에도 이러한 스케줄 정보를 유지할 필요가 있다면, 두 번째 유형의 JobStore을 사용해야 할 것이다.

   

두 번째 타입의 JobStore는 실제로 Quartz 프레임워크에서 두 가지의 서로 다른 형태로 구현되어 제공되고 있지만, 이 둘 모두 일반적으로 JDBC JobStore로 일컬어지고 있다. 이 두 가지 모두의 JDBC JobStore는 JDBC 드라이버를 사용하며, 스케줄 정보를 유지하고 있는 관계형 데이터베이스로부터 정보를 가져온다. 이 두 가지 타입은 데이터베이스 트랜잭션을 제어하는지의 여부나 BEA의 WebLogic이나 JBoss와 같은 어플리케이션 컨테이너에 제어를 넘기는지의 여부에 그 차이점이 존재한다 (이는J2EE에서의 BMT와 CMT 사이의 차이점과 유사하다).

   

두 가지 유형의 JDBC JobStore는 다음과 같다.

   

● JobStoreTX: 트랜잭션을 제어하고 싶은 경우나, 서버 환경 없이 어플리케이션을 운영하려 할 때 사용된다.

● JobStoreCMT: 어플리케이션 서버 환경 내에서 어플리케이션이 운영되며 컨테이너가 트랜잭션을 관리하도록 하고 싶은 경우 사용된다.

   

JDBC JobStore는 어플리케이션이 중지되고 다시 시작된 후에라도 스케줄링 정보를 유지하여 Scheduler가 실행되도록 만들어야 할 경우를 위해 설계되었다.

   

Job and Triggers

Quartz 설계자들은 Job과 스케줄을 분리하였다. Quartz에서 Trigger는 Job이 트리거링 되거나 발생되어야 할 때, Scheduler에게 알려주는데 사용된다. Quartz 프레임워크에서는 간단한 Trigger 타입들을 제공하고 있는데, SimpleTrigger와 CronTrigger가 가장 일반적으로 사용된다.

   

SimpleTrigger는 스케줄을 간단히 발생시키는데 사용될 목적으로 설계되었다. 일반적으로, 주어진 시간에 Job을 발생시켜 (m)초 간격을 두고 여러 번(n) 이를 실행할 필요가 있을 경우, SimpleTrigger가 적합한 선택이 된다. 반면, Job에 요구되는 스케줄링이 복잡할 경우, CronTrigger가 적합할 것이다.

   

CronTrigger는 달력과 유사한 스케줄에 기반하고 있다. 만약 여러분의 Job이 매주 토요일과 일요일을 제외한, 매일 오전 10시30분마다 실행되어야 하는 경우에, CronTrigger가 사용된다. 이 이름이 암시하고 있듯, CronTrigger는 Unix의 cron 표현식을 기반으로 하고 있다. 예를 들면, 다음의 Quartz cron 표현식은 월요일부터 금요일에 걸쳐 매일 오전 10시 15분에 Job을 실행할 것이다.

   

0 15 10 ? * MON-FRI

   

그리고 다음 표현식은 2002, 2003, 2004, 2005년 동안 매월 마지막 금요일 오후 10시 15분에 Job을 실행할 것이다.

   

0 15 10 ? * 6L 2002-2005

   

이러한 작업은 SimpleTrigger로  수행할 수 없다. 이 둘 모두 Job에 사용될 수 있다. 어떠한 것을 사용할 지에 관한 선택은 스케줄링 될 작업 성격에 달려 있다.

   

Scheduling a Job

이제 예제 Job을 살펴보면서 실제 사용에 관한 부분에 대해 토의해보자. 클라이언트가 자신의 FTP 사이트에 파일을 저장할 때마다 부서에 전자 메일로 통지할 필요가 있는 상황을 여러분이 관리하고 있다고 가정해보자. 우리의 Job은 원격 서버에 있는 파일들을 다운로드 하는 것이 된다. 그런 후, Job은 발견된 파일들의 다운로드 횟수를 포함하고 있는 전자 메일을 전송하게 된다. 이Job은 누군가가 하루 동안 이러한 작업을 수작업으로 전송할 필요가 없도록 편리하게 만들어준다. 우리는 이러한 Job이 일주일 내내 하루 24시간 동안 매 60초마다 검사하도록 설정할 수 있다. 이는 바로 Quartz 프레임워크를 완벽하게 사용하는 예이다.

   

첫 번째 단계는 FTP와 Email 로직을 수행하는 Job 클래스를 작성하는 것이다. 다음 예제는 Quartz Job 클래스를 나타낸 것으로, org.quartz.Job 인터페이스를 구현하고 있다.

   

예제 2. FTP 사이트에서 파일들을 다운로드 받고 Email을 전송하는 Quartz Job

   

public class ScanFTPSiteJob implements Job {

    private static Log logger = LogFactory.getLog(ScanFTPSiteJob.class);

   

    /*

     * 정확한 시간에 스케줄러 프레임워크에 의해 호출된다.

    */

    public void execute(JobExecutionContext context) throws JobExecutionException {

        JobDataMap jobDataMap = context.getJobDataMap();

   

        try {

            // FTP 사이트에서 파일들 검사

            File[] files = JobUtil.checkForFiles(jobDataMap);

            JobUtil.sendEmail(jobDataMap, files);

        } catch (Exception ex) {

            throw new JobExecutionException(ex.getMessage());

        }

    }

}

   

이 글에서는 일부러 ScanFTPSiteJob을 매우 간단하게 구성하였다. 또한 이 글에서는 이 예제를 위해 JobUtil이라는 유틸리티 클래스를 작성하였다. 이 클래스는 Quartz의 부분이 아니지만, 다양한 Job들에서 재사용 할 수 있는 여러분만의 유틸리티 성격의 라이브러리를 만드는 것이 좋다. 이 글에서는 Job 클래스와 Quartz Scheduler 내부에 모든 코드들을 쉽게 둘 수도 있었지만, Quartz를 사용하는 것 때문에 재사용을 고려하지 않을 수는 없었다.

   

JobUtil.checkForFiles()와 JobUtil.sendEmail()이 사용하는 파라미터들은 JobDataMap 객체를 사용하고 있는데, 이 객체는Quartz가 생성한 객체이다. 이 인스턴스는 Job이 실행될 때마다 생성되며, 이를 사용해 Job 클래스로 환경 설정 파라미터들을 넘겨준다.

   

JobUtil의 구현 부분은 여기에 나타내지 않았지만, 우리는 FTP와 Email 기능을 모두 구현하고 있는 Jakarta의 Commons Net을 통해 매우 쉽게 사용할 수 있었다.

   

Calling Your Jobs with the Scheduler

Job을 생성하는 것이 첫 번째 작업이지만, Scheduler에 의해 Job이 호출되도록 하기 위해서는 Scheduler에게 얼마나 자주, 언제 Job이 호출되어야 하는지 알려주어야 한다. 이 작업은 Trigger를 Job에 연관시킴으로써 이루어진다. 우리는 Scheduler가 계속 매 60초마다 Job을 호출하는데 관심을 두고 있기 때문에, SimpleTrigger를 사용할 것이다.

   

Job과 Trigger의 스케줄은 Quartz Scheduler 인터페이스를 통해 이루어진다. Scheduler의 인스턴스를 얻기 위해서는 팩토리로부터 인스턴스를 얻어와야 한다. 이를 위한 가장 쉬운 방법은 StdSchedulerFactory 클래스의 static 메소드인getDefaultScheduler()를 호출하는 것이다.

   

Quartz 프레임워크를 사용할 때, 반드시 start() 메소드를 호출하여 Scheduler를 시작시켜야 한다. 예제 3에 있는 코드는 대부분의 Quartz 어플리케이션의 일반적인 패턴을 따르고 있다. 대부분의 Quartz 어플리케이션에서는, 하나 또는 그 이상의 Job들을 생성하고 Trigger들을 생성하고 설정한 후, Scheduler에 Job과 Trigger들에 대한 스케줄을 정하고 Scheduler를 시작시킨다(주: Scheduler를 먼저 시작시켜도 된다. 이는 중요하지 않다).

   

예제 3. Quartz Job들은 Quartz Scheduler를 통해 스케줄이 지정되어야 한다.

   

public class MyQuartzServer {

    public static void main(String[] args) {

        MyQuartzServer server = new MyQuartzServer();

   

        try {

            server.startScheduler();

        } catch(SchedulerException ex) {

            ex.printStackTrack();

        }

    }

   

    protected void startScheduler() throws SchedulerException {

        // 팩토리를 사용해 Scheduler 인스턴스를 생성

        Scheduler scheduler = StdSchedulerFactory.getDefaultScheduler();

   

        // JobDetail은 Job들에 대한 정의를 포함한다.

        JobDetail jobDetail = new JobDetail("ScanFTPJob", Scheduler.DEFAULT_GROUP,

                                          ScanFTPSiteJob.class);

        // execute() 내에서 사용될 job 파라미터들을 저장

        jobDetails.getJobDataMap().put("FTP_HOST", "\home\cavaness\inbound");

   

        // 여기에 Job 파라미터들에 필요한 기타 다른 내용들이 온다.

   

        // 매 60초마다 발생하는 Trigger 인스턴스 생성

        Trigger trigger = TriggerUtils.makeSecondlyTrigger(60);

   

        // Scheduler에 Job과 Trigger를 설정

        scheduler.scheduleJob(jobDetail, trigger);

   

        // Scheduler 실행 시작

        scheduler.start();

    }

}

   

Programmatic vs. Declarative Scheduling

예제 3에서, 우리는 프로그래밍을 통해 ScanFTPSiteJob 스케줄을 작성했다. 즉, Scheduler에 Job과 Trigger를 설정하기 위해 자바 코드를 사용하였다는 의미이다. Quartz 프레임워크에서는 XML 파일들에 Job 스케줄을 선언적으로 설정할 수 있는 기능을 지원하고 있다. 선언적인 접근 방법을 통해 어떠한 Job이 언제 실행되어야 하는지를 보다 빠르게 지정할 수 있다.

   

Quartz 프레임워크에는 Quartz 어플리케이션이 시작하자마자, Job과 Trigger 정보를 포함하고 있는 XML 파일을 읽어 들이는"플러그 인"을 포함하고 있다. XML 내에 있는 모든 Job들은 이들과 관련된 Trigger들과 함께 Scheduler에 추가된다. 물론 Job클래스들을 작성해야 하지만, 그러한 Job들을 갖는 Scheduler의 환경을 설정하는 것은 매우 동적으로 이루어진다. 예제 4는 예제 3의 코드에 있는 동일한 로직을 수행하는데, 선언적인 방법으로 구성되어 있다.

   

예제 4. Quartz Job들은 XML 파일을 사용하여 스케줄링 될 수 있다.

   

<?xml version="1.0" encoding="utf-8"?>

<quartz>

    <job>

        <job-detail>

            <name>ScanFTPSiteJob</name>

            <group>DEFAULT</group>

            <description>A job that scans an ftp site for files</description>

            <job-class>ScanFTPSiteJob</job-class>

   

            <job-data-map allows-transient-data="true">

                <entry>

                    <key>FTP_HOST</key>

                    <value>homecavanessinbound</value>

                </entry>

   

                <!-- 다른 필요한 Job 파라미터들을 여기에 둔다 -->

            </job-data-map>

        </job-detail>

   

        <trigger>

            <simple>

                <name>ScanFTPSiteJobTrigger</name>

                <group>DEFAULT</group>

                <job-name>ScanFTPSiteJob</job-name>

                <job-group>DEFAULT</job-group>

                <start-time>2005-09-11 6:10:00 PM</start-time>

                <!-- 계속 60초마다 반복 실행 -->

                <repeat-count>-1</repeat-count>

                <repeat-interval>60000</repeat-interval>

            </simple>

        </trigger>

    </job>

</quartz>

   

예제 4에 있는 XML 엘리먼트들을 예제 3에 있는 자바 코드와 비교해볼 수도 있다. 이들은 개념적으로 동일하다. 예제 4에 보여지는 것과 같은 선언적인 접근 방법의 장점은 유지보수가 매우 간단해진다는 것이다. XML 파일만 변경하고 Quartz 어플리케이션을 재 시작 하기만 하면 되기 때문이다. 소스 코드를 수정하고 재 컴파일 하여 배포할 필요가 없다.

   

Stateful and Stateless Jobs

이 글에서 살펴보았던 Quartz Job 예제는 모두 상태 정보를 가지고 있지 않다. 즉, 각각의 Job이 실행에 대해, Job이 실행되는 동안 JobDataMap에 가해진 어떠한 변경 사항들도 유지되지 않는다는 것을 의미한다. 만약 JobDataMap에 값을 추가, 변경 또는 삭제하는 기능이 필요하며, 다음 실행에 이러한 변경 사항들이 Job에 반영되도록 해야 한다면, Quartz Stateful Job이 필요하다.

   

만약 여러분이 EJB 개발을 경험해 보았다면, Stateful이라는 것이 부정적인 의미를 담고 있다는 점 때문에 여러분은 지금 움찔하고 있을 것이다. 이는 주로 "Stateful EJB"가 가지고 있는 확장성 이슈로부터 기인한다. Quartz Stateful Job은org.quartz.StatefulJob 인터페이스를 통해 구현된다. Stateless Job과 Stateful Job 간의 주요 차이점은, Stateful Job은 한 번에Job을 실행하는 인스턴스가 오직 하나를 가질 수 있다는 점이다. 그러므로, 예제 3의 경우, "ScanFTPJob" Job을 실행하는 인스턴스는 한 번에 하나만 가지게 된다. 대부분의 경우, 이는 커다란 문제점을 나타내지는 않는다. 그러나, 만약 자주 실행될 필요가 있는 Job을 가지고 있다거나, 작업 완료까지 오랜 시간을 필요로 하는 Job을 가지고 있을 경우, Stateful Quartz Job은 확장성에 문제를 가져다 줄 수 있다.

   

Other Features of the Quartz Framework

Quartz 프레임워크는 매우 다양한 기능들을 가지고 있다. 사실, 한 번에 이 모든 기능들을 나열하기에는 너무나 많다. 다음 목록은 이 글에서는 자세히 언급할 시간이 없는 Quartz 내의 여러 기능들 중 몇몇을 간단하게나마 설명한 것이다.

   

Listeners and Plugins

오늘날 어떠한 오픈 소스 프레임워크라도 사용하고 있는 개념이 바로 이 둘이다.

   

Quartz Listener는 주요 이벤트가 발생할 때, 프레임워크 내부로부터 콜백을 받는 자바 클래스이다. 예를 들면, Job이 스케줄 되어 있거나 스케줄 되어 있지 않을 때, 또는 Trigger가 끝났거나, 더 이상 발생시키지 않을 때, 이러한 모든 것들은 Listener로 통지되도록 설정될 수 있다. Quartz 프레임워크는 Scheduler, Job, Trigger들을 위한 Listener들을 포함하고 있다. 또한, Job Listener와 Trigger Listener들을 특정한 한 Job이나 Trigger에 적용되도록 만들거나 전체에 걸쳐 적용되도록 설정할 수도 있다.

   

일단 Listener가 호출되면, 이 정보를 사용해 Listener 클래스 내에서 수행하려는 어떠한 로직이라도 실행시킬 수 있다. 예를 들면, 만약 Job이 완료될 때마다 전자 메일을 보내고 싶은 경우, 이를 Job에 프로그래밍 해 넣을 수 있다. 또한, JobListener를 사용할 수도 있다. 이 JobListener는 결합도를 느슨하게 만들어 보다 나은 설계를 만들어주는데 도움을 줄 수도 있다.

   

Quartz Plugin은 Quartz 소스를 수정하지 않고도 Quartz 프레임워크에 기능을 추가시켜주는 새로운 기능이다. 이것은 Quartz프레임워크를 확장해야 하는데, 변경한 기능을 Quartz 개발 팀에게 보내주고 다음 버전에 반영되기까지 기다릴 시간이 없는 개발자들을 위한 기능이다. 여러분이 Struts 플러그 인에 익숙하다면, Quartz 플러그 인을 사용하는 방법을 더 쉽게 이해할 수 있을 것이다.

   

Clustering Quartz Applications

Quartz 어플리케이션은 여러분의 요구 사항에 따라 수직/수평적으로 모두 클러스터링 될 수 있다. 클리스터링을 통해 다른 클러스터링 타입과 마찬가지의 이점들을 제공받을 수 있다.

   

● 확장성

● 높은 가용성

● 로드 밸런싱

   

현재 Quartz는 관계형 데이터베이스와 JDBC JobStore중 하나의 도움을 통해 클러스터링을 지원한다. 향후 버전에서는, 이러한 제한이 사라져, 데이터베이스 없이도 RAMJobStore에서 사용 가능해질 것이다.

   

The Quartz Web Application

Quartz 프레임워크를 2-3주나 몇 달간 사용한 후 보통 Quartz 사용자들이 가장 많이 요구하는 것들 중 하나는 Quartz를 GUI에 통합하는 것에 대한 것이다. 자바 서블릿을 사용하여 Quartz를 초기화 하고 시작시킬 수 있는 기능이 현재 프레임워크에 제공되고 있다. 일단 여러분이 Scheduler 인스턴스에 접근하게 되면, 이 인스턴스는 웹 컨테이너의 ServletContext에 저장하고Scheduler 인터페이스를 통해 스케줄링 환경을 관리할 수 있다.

   

다행히도, 몇몇 Quartz 개발자들은 Quartz Scheduler 환경을 보다 잘 관리하는데 사용될 수 있는 독립형 Quartz Web Application에 대해 작업해 오고 있다. Struts와 Spring과 같은 다수의 유명한 오픈 소스 프로젝트를 기반으로 구축되어 이 GUI는 많은 기능들을 지원하는데, 이들은 간단한 인터페이스에 랩핑 되어 있다. 그림 1은 이 GUI를 잡아낸 것이다.

   

   

그림 1. Quartz 환경을 보다 쉽게 관리해주는데 도움을 주는 Quartz Web Application

   

What's down the Road?

이미 다음 주요 릴리즈에 대한 움직임도 진행되고 있을 정도로 Quartz 프로젝트는 활발하게 진행되고 있다. OpenSymphony의wiki에서 Quartz 2.0에서 고려되고 있는 기능들과 설계에 대한 정보를 얻을 수도 있다.

   

항상 그렇듯이, 날마다 Quartz 사용자들은 프레임워크에서 고려될 수 있는 갖가지 기능들에 대한 제안이나 설계에 관해 자유롭게 제안하고 있다.

   

Find Out More about Quartz

Quartz 프레임워크의 보다 많은 기능들을 사용해 나갈수록, User and Developer Forum은 Quartz 사용자들과의 질문/답변 및 커뮤니케이션을 위한 매우 유용한 자원이 될 것이다.

   

출처 : http://blog.empas.com/kkamdung/12297998

[출처] Quartz - java 스케쥴러|작성자 순짱

 

===================================================================================

 

가끔 서버에서 주기적으로 어떠한 작업을 하고자 할때 리눅스에서는 크론탭을 사용하여 주기적으로 어떠한 작업을 처리합니다.
이런 주기적 작업을 처리하기위해 Spring에서 지원해 주는 Quartz스케쥴러를 통해 크론탭과 같은 역할을 하는 스케쥴러를 작성할 있습니다.
이번에는 Spring Quartz 연동하여 스케줄러를 작성해 보겠습니다.

작업순서는 
스프링 기본 세팅 -> Quartz 세팅 순으로 작업하겠습니다.

1.
스프링 기본 설정
1) springframework.org 
이동하셔서 스프링 라이브러리를 다운 받습니다

위와 같은 페이지가 뜨면 해당사항을 입력하시고 Access Download 클릭하셔서 다운로드 페이지로 이동합니다. (귀찮으신 분들은 하단의 파란색으로 "download page" 선택하시면 입력하시지 않고도 다운로드 페이지로 이동하실수 있습니다.

많은 버전의 라이브러리  spring-framework-2.5.6.SEC02.zip  다운 받습니다. 다른 버전을 다운 받으셔도 상관없습니다만 버전에 따라 세팅 내용이 조금 달라지므로 같은 버전의 라이브러리로 진행하는 것이 나을 것같네요~^^.

2)
이렇게 라이브러리까지 다운로드 받고 나면 Eclipse 같은 IDE에서 Dynamic Web Project 선택하여 Project 한개 생성합니다.
(
저는 SpringQuartz 라는 이름으로 생성했습니다.)

3)
프로젝트가 생성되면 프로젝트 안에 /WEB-INF/lib 디렉토리에 스프링 라이브러리를 압축 곳에 있는 dist/spring.jar 파일을 추가합니다.
*
 : 프로젝트를 진행하다 보면 위와같이 라이브러리 버전이 없는 jar파일을 그냥 추가하는 경우가 있는데 나중에 라이브러리를 업데이트 해야 할일이 생기게 되면 위와같이 spring.jar 라고 되어있으면 지금 적용되어 있는 버전이 인지 알수가 없습니다. 그렇기 때문에 항상 라이브러리 추가하실때는 추가하시는 라이브러리의 버전 번호를 파일이름 뒤에 추가하는 습관 들이 시는게 좋습니다
     ex) spring-2.5.6.jar

4)
프로젝트 안에 생성된 web.xml Spring 사용하기 위한 세팅을 추가해 줍니다.
*
저는
Quartz 사용하기 위한 최소한의 Spring 세팅을 해놓았기 때문에 세팅 내용이 단순합니다. 만약 웹프로젝트와 함께 Quartz 사용하신다면 웹에 맞게 설정하시고 사용하셔야 함을 알려드립니다.^^

<?xml version="1.0" encoding="UTF-8"?>

<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

xmlns="http://java.sun.com/xml/ns/javaee"

xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee

http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" id="WebApp_ID" version="2.5"> <listener>

<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>

</listener>

<context-param>

<param-name>contextConfigLocation</param-name>

<param-value>/WEB-INF/config/applicationContext*.xml</param-value>

</context-param>

</web-app>


5) 쿼츠 라이브러리를 다운로드 받고 라이브러리를 추가해 줍니다.
쿼츠 라이브러리 다운로드 하신다음 압축을 풀어 줍니다.
해당 라이브러리를 프로젝트의 lib 디렉토리에 복사하여 넣어줍니다.
- quartz-all-1.8.3.jar
-
압축푼 lib 디렉터리의 log4j-1.2.14.jar
-
압축푼 lib 디렉터리의 slf4j-api-1.5.10.jar
-
압축푼 lib 디렉터리의 slf4j-log4j12-1.5.10.jar
추가 줍니다.
마지막으로 apache 
commons-logging-1.1.1.jar 
다운로드 하셔서 위와 같이 프로젝트의 lib 추가해주시면 라이브러리 추가는 끝이 납니다.

6) Quartz
핵심적인 기능을 /WEB-INF/config/applicationConext.xml 작성합니다.
스케쥴러의 핵심 세팅은 3가지 정도 입니다.
하나. 실제 주기적으로 실행될 클래스 등록
. 스케줄러가 동작하는 interval time 설정
. 실제 동작하게  설정

이런 세가지가 있겠습니다.

스케줄러 동작방식에는 두가지가 존재 합니다.
-Simple : interval time
간단하게 동작하는 방식으로 몇초, 혹은 몇분, 몇시간 단위로 작동하고 싶을때 사용합니다
<Simple type setting>

<?xml version="1.0" encoding="UTF-8" ?>

<beans xmlns="http://www.springframework.org/schema/beans"

  xmlns:context="http://www.springframework.org/schema/context"

  xmlns:p="http://www.springframework.org/schema/p"

  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-2.5.xsd

                           http://www.springframework.org/schema/context

                           http://www.springframework.org/schema/context/spring-context-2.5.xsd">

<!-- 하나.주기적으로 실행될 클래스 설정 -->

<!-- property name은 jobClass로 fix, value는 사용자가 작성한 class 파일 위치 -->

<bean id="simpleQuartzJob" class="org.springframework.scheduling.quartz.JobDetailBean">

<property name="jobClass" value="net.test.quartz.SimpleQuartzJob"/>

</bean>


<!-- 둘.스케줄러의 interval time 설정 -->

<!-- 쿼츠에는 아래와 같이 몇초에 한번씩 돌게 하는 Simple type 과 -->

<!-- 무슨 요일 몇시에 한번씩 돌게 하는 날짜로 지정하는 Cron type 이 있다. -->

<!-- 현재는 Simple type으로 세팅 -->

<!-- jobDetail은 위에서 설정한 실제 동작할 클래스 id를 적어준다 -->

<!-- startDelay는 서버 시작후 몇초 뒤에 시작할지 세팅(ms 단위)  -->

<!-- repeatInterval은 몇 초에 한번씩 실행될 건지 세팅(ms 단위: 현재 1초) -->

<bean id="simpleTrigger" class="org.springframework.scheduling.quartz.SimpleTriggerBean">

<property name="jobDetail" ref="simpleQuartzJob"/>

<property name="startDelay" value="1000"/>

<property name="repeatInterval" value="1000"/>

</bean>

<!--셋. 실제 동작하게끔 설정 -->

<!--ref bean은 위에서 설정한 interval time 아이디를 넣어주면 됨  -->

<bean class="org.springframework.scheduling.quartz.SchedulerFactoryBean">

<property name="triggers">

<list>

<ref bean="simpleTrigger"/>

</list>

</property>

<!-- Quartz 실행시 세팅 -->

<property name="quartzProperties">

<props>

<prop key="org.quartz.threadPool.class">org.quartz.simpl.SimpleThreadPool</prop>

    <prop key="org.quartz.threadPool.threadCount">5</prop>

    <prop key="org.quartz.threadPool.threadPriority">4</prop>

    <prop key="org.quartz.jobStore.class">org.quartz.simpl.RAMJobStore</prop>

    <prop key="org.quartz.jobStore.misfireThreshold">60000</prop>

</props>

</property>

</bean>

</beans>



-Cron : linux Cron tab 같은 역할을 하는 타입니다. 몇월, 몇일 몇시에 동작하게 하고 싶으면 Cron type 사용하시면 됩니다<?xml version="1.0" encoding="UTF-8" ?>.
<Cron type setting>

<beans xmlns="http://www.springframework.org/schema/beans"

  xmlns:context="http://www.springframework.org/schema/context"

  xmlns:p="http://www.springframework.org/schema/p"

  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-2.5.xsd

                           http://www.springframework.org/schema/context

                           http://www.springframework.org/schema/context/spring-context-2.5.xsd">

<!--하나. 주기적으로 실행될 클래스 설정 -->

<bean id="cronQuartzJob" class="org.springframework.scheduling.quartz.JobDetailBean">

<property name="jobClass" value="net.test.quartz.CronQuartzJob"/>

</bean>

<!--둘. 스케줄러의 interval time 설정-->

<!--cronExpression을 통해서 스캐줄러 주기를 설정한다. -->

<bean id="cronTrigger" class="org.springframework.scheduling.quartz.CronTriggerBean">

<property name="jobDetail" ref="cronQuartzJob"/>

<property name="cronExpression" value="0/1 * * * * ?"/>

</bean>

<!--셋. 실제 동작하게끔 설정 -->

<bean class="org.springframework.scheduling.quartz.SchedulerFactoryBean">

<property name="triggers">

<list>

<ref bean="cronTrigger"/>

</list>

</property>

<property name="quartzProperties">

<props>

<prop key="org.quartz.threadPool.class">org.quartz.simpl.SimpleThreadPool</prop>

    <prop key="org.quartz.threadPool.threadCount">5</prop>

    <prop key="org.quartz.threadPool.threadPriority">4</prop>

    <prop key="org.quartz.jobStore.class">org.quartz.simpl.RAMJobStore</prop>

    <prop key="org.quartz.jobStore.misfireThreshold">60000</prop>

</props>

</property>

</bean>

</beans>


Cron type 사용하려면 CronExpression 알아야 합니다.

*Cron Expression
cron expression
각각의 필드는 다음을 나타낸다.(왼쪽 -> 오른쪽 )

 필드 이름

 허용

 허용된 특수 문자

 Seconds

 0 ~ 59

 , - * /

 Minutes

 0 ~ 59

 , - * /

 Hours

 0 ~ 23

 , - * /

 Day-of-month

 1 ~ 31

 , - * ? / L W

 Month

 1 ~12 or JAN ~ DEC

  , - * /

 Day-Of-Week

 1 ~ 7 or SUN-SAT

 , - * ? / L #

 Year (optional)

 empty, 1970 ~ 2099

 , - * /


Cron Expression
특수문자
'*' :
모든 수를 나타냄. 분의 위치에 * 설정하면 " 마다" 라는 .
'?' : day-of-month
day-of-week 필드에서만 사용가능. 특별한 값이 없음을 나타낸다.
'-' : "10-12"
같이 기간을 설정한다. 시간 필드에 "10-12" 이라 입력하면 "10, 11, 12시에 동작하도록 설정" 이란 .
',' : "MON,WED,FRI"
같이 특정 시간을 설정할 사용한다. "MON,WED,FRI" 이면 " ',,' 에만 동작" 이란 .
'/' :
증가를 표현합니다. 예를 들어 단위에 "0/15" 세팅 되어 있다면 "0 부터 시작하여 15 이후에 동작" 이란 .
'L' : day-of-month
day-of-week 필드에만 사용하며 마지막날을 나타냅. 만약 day-of-month "L" 되어 있다면 이번 달의 마지막에 실행하겠다는 것을 나타냄.
'W' : day-of-month
필드에만 사용되며, 주어진 기간에 가장 가까운 평일(~) 나타낸다. 만약 "15W" 이고 이번 달의 15일이 토요일이라면 가장가까운 14 금요일날 실행된다. 15일이 일요일이라면 가장 가까운 평일인 16 월요일에 실행되게 된다. 만약 15일이 화요일이라면 화요일인 15일에 수행된다.
"LW" : L
W 결합하여 사용할 있으며 "LW" "이번달 마지막 평일" 나타냄
"#" : day-of-week
사용된다. "6#3" 이면 3(3)번째 금요일(6) 이란 뜻이된다.1 일요일 ~ 7 토요일 

 Expression

 Meaning

 "0 0 12 * * ?"

 매일 12시에 실행

 "0 15 10 ? * *"

 매일 10 15분에 실행

 "0 15 10 * * ?"

 매일 10 15분에 실행

 "0 15 10 * * ? *"

 매일 10 15분에 실행

 "0 15 10 * * ?  2010" 

 2010 동안 매일 10 15분에 실행

 "0 * 14 * * ?"

 매일 14시에서 시작해서 14:59 끝남

 "0 0/5 14 * * ?"

 매일 14시에 시작하여 5 간격으로 실행되며 14:55분에 끝남

 "0 0/5 14,18 * * ?"

 매일 14시에 시작하여 5 간격으로 실행되며 14:55분에 끝나고, 매일 18시에 시작하여 5분간격으로 실행되며 18:55분에 끝난다.

 "0 0-5 14 * * ?"

 매일 14시에 시작하여 14:05 분에 끝난다.


*
시간에 맞춰 돌아가는 스케줄러에서 다른 클래스를 사용하고 싶을 때는 다음과 같이 설정합니다.

<!-- 스프링 DI : 사용할 Service 객체를 생성 -->

<bean id="quartzJobService" class="net.test.quartz.service.impl.QuartzJobServiceImpl"/>


<bean id="simpleQuartzJob" class="org.springframework.scheduling.quartz.JobDetailBean">

<property name="jobClass" value="net.test.quartz.SimpleQuartzJob"/>

<!-- 사용하고자 하는 class의 bean id를 등록 -->

<property name="jobDataAsMap">

<map>

<entry key="quartzJobService">

<ref local="quartzJobService"/>

</entry>

</map>

</property>

</bean>



 *두가지 스케줄러를 동시에 실행 시킬때

<bean class="org.springframework.scheduling.quartz.SchedulerFactoryBean">

<property name="triggers">

<!--트리거를 두개 생성후 아래와 같이 세팅 -->

<list>

<ref bean="simpleTrigger"/>

<ref bean="cronTrigger"/>

</list>

</property>

<property name="quartzProperties">

<props>

<prop key="org.quartz.threadPool.class">org.quartz.simpl.SimpleThreadPool</prop>

    <prop key="org.quartz.threadPool.threadCount">5</prop>

    <prop key="org.quartz.threadPool.threadPriority">4</prop>

    <prop key="org.quartz.jobStore.class">org.quartz.simpl.RAMJobStore</prop>

    <prop key="org.quartz.jobStore.misfireThreshold">60000</prop>

</props>

</property>

</bean>



7) 실제 작동할 Class파일 생성

package net.test.quartz;


import net.test.quartz.service.QuartzJobService;


import org.quartz.JobExecutionContext;

import org.quartz.JobExecutionException;

import org.springframework.scheduling.quartz.QuartzJobBean;


public class SimpleQuartzJob extends QuartzJobBean{

//실행될 클래스는 꼭 QuartzJobBean을 상속받아야 되며 

//executeInternal method를 override 하면 자동으로 이 메소드가 실행


//Spring의 DI를 사용하여 Service객체를 setting

//DI를 사용하지 않는다면 필요 없는 부분

private QuartzJobService quartzJobService;

public void setQuartzJobService(QuartzJobService quartzJobService) {

this.quartzJobService = quartzJobService;

}



@Override

protected void executeInternal(JobExecutionContext ex)throws JobExecutionException {

quartzJobService.printLog();

}

}


위와 같은 방식으로 Spring Quartz 사용하여 스케줄러를 사용할 있습니다.

함께 업로드 하는 파일은 제가 직접 작업한 프로젝트이구요. 함께 확인 보시면 쉽게 쿼츠를 사용하실수 있으실 겁니다.~^^

 SpringQuartz.war

 

출처 - http://javastore.tistory.com/96


===================================================================================


매번 cronTab 으로 배치작업을 실행시키며, 이게 아직 쓰는 놈인지, 언제 만들었는지,
수정하기 번거롭네 등 에로사항이 많았으.. 기억도 안나고.. 그때그때 만든 것들은 버전관리도 안되고,,
해서. 스프링 프로젝트이니, 스프링에서 동작하는 배치를 쓰는게 낫겠다는 생각이 들어 이참에, 배치를 몽땅 quartz
로 만들어서 정리를 해야겠다는 생각이 들었심.

스프링 프로젝트 환경이 세팅이 되어있다고 치고,

 

*필자의 경우는
Dynamic Web Project 로 qbatch 라는 프로젝트를 만들었고,


디렉토리 구조는
qbatch
  |_src
  |_WebContent
          |_index.jsp
          |_META-INF
          |_WEB-INF
              |_classes
              |_lib
              |_views
              |_action-servlet.xml
              |_web.xml
             
이렇게 되어있고,
src 폴더에는 비지니스를 구현한 java 파일들(cotroller/service/dao 등),
classes 에는 src 의 컴파일된 class 파일들 과 applicationContext.xml 및 각종 properties 파일들,
lib 폴더에는 spring.jar, activation.jar, log4j.jar, mysql-connector-java-xxx.jar 등이,
views 에는 각종 jsp 파일들이 위치해있다.

 

암튼 시작해보면,

 

1. 일단 quartz 라이브러리를 다운받는다.
http://terracotta.org/downloads/open-source/destination?name=quartz-1.8.5.tar.gz&bucket=tcdistributions&file=quartz-1.8.5.tar.gz
압축을 풀고 quartz-all-1.8.5.jar 파일을 찾아서
WEB-INF/lib 폴더 밑에 복사해 넣으면 준비끝.

 

2. 실제 비지니스를 실행할 java 파일을 만든다.           
나의 비지니스 로직은 System.out.println("음. 배치가 실행되었구만~!!!!"); 이다.
이 로직만 빼고, 나머지는 코드는 동일하게 쓰면되심.

src/com/batch/service/SystemOutTestService.java 를 아래와같이 만든다.

 

 

package com.batch.service;

import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.springframework.scheduling.quartz.QuartzJobBean;

public class SystemOutTestService extends QuartzJobBean {
 
 
 @Override
 protected void executeInternal(JobExecutionContext arg0) throws JobExecutionException {
  try {
   
   System.out.println("음. 배치가 실행되었구만~!!!!");
  } catch (Exception e) {
   e.printStackTrace();
  }
  
 }

}

 


3. 이제 저 SystemOutTestService.java 가 실행스케줄링 되도록 applicationContext.xml 을 만져주자.
1. 실행할 비지니스로직 클래스를 빈으로 등록.
2. 해당빈이 스케줄을 만들 트리거 설정
3. 실제 동작되도록 설정.

이렇게 3가지만 세팅하면 되심. 아래와같이.

<beans 어쩌구저쩌구.... >

<!-- 1. 실행할 비지니스로직 클래스를 빈으로 등록. -->
<bean id="SystemOutTest" class="org.springframework.scheduling.quartz.JobDetailBean">
 <property name="jobClass" value="com.batch.service.SystemOutTestService"/>
 </bean>

<!-- 2. 해당빈이 스케줄을 만들 트리거 설정 -->
 <bean id="SystemOutTestTrigger" class="org.springframework.scheduling.quartz.SimpleTriggerBean">
  <property name="jobDetail" ref="SystemOutTest"/>
  <property name="repeatInterval" value="3000"/> <!--  every 1000(1초)  -->
  <property name="startDelay" value="2000" /><!--  at first execution 2000(2초) 후에 실행  -->
 </bean>
 
<!-- 3. 실제 동작되도록 설정. -->
 <bean class="org.springframework.scheduling.quartz.SchedulerFactoryBean" autowire="no">
  <property name="triggers">
   <list>
    <ref bean="SystemOutTestTrigger"/>
   </list>
  </property>
  <property name="quartzProperties">
   <props>
    <prop key="org.quartz.threadPool.class">org.quartz.simpl.SimpleThreadPool</prop>
    <prop key="org.quartz.threadPool.threadCount">5</prop>
    <prop key="org.quartz.threadPool.threadPriority">4</prop>
    <prop key="org.quartz.jobStore.class">org.quartz.simpl.RAMJobStore</prop>
    <prop key="org.quartz.jobStore.misfireThreshold">600000</prop>
   </props>
  </property>
 </bean>
 
 
이제 톰캣 재시작 하면 3초마다 "음. 배치가 실행되었구만~!!!!" 이라고 찍힐거임.
비지니스 로직이 넘 초라하니, 클래스 추가하여 실제 필요한 동작을 하게끔 비지니스 로직에
시간을 들이심이 좋을듯 해서 초간단으로 적었심. 더 세심한 설정은 구글형이나 네이년에
물어보시면 찾으실 수 있으실거임.


출처 - http://jejoong76.blog.me/70125014485


===================================================================================


Spring에서 Quartz JOB 설정 예제

  • 한 시간에 한번 keyGeneratorJob을 실행 시키는 예제 입니다.

applicationContext.xml 설정

<bean id="keyPool" class="com.oracleclub.web.support.KeyPool" init-method="init" lazy-init="true">
  <property name="keySize" value="1000"/>		
</bean>

<!-- jobClass 설정 -->
<bean id="keyGeneratorJob" class="org.springframework.scheduling.quartz.JobDetailBean">
  <property name="jobClass" value="com.oracleclub.web.job.KeyGeneratorJob"/>
  <property name="jobDataAsMap">
	<map>
      <entry key="keyPool">
   	    <ref bean="keyPool"/>
  	  </entry>
 	</map>
  </property>
</bean>

<!-- jobTrigger 설정 -->
<bean id="keyGeneratorTrigger" class="org.springframework.scheduling.quartz.SimpleTriggerBean">
  <property name="jobDetail" ref="keyGeneratorJob" />
  <!--  1000 == 1 second, 60minuts=3600000, 1day=86400000-->
  <property name="startDelay" value="3600000" />
  <property name="repeatInterval" value="3600000" />
</bean>

<bean id="schedulerFactory" class="org.springframework.scheduling.quartz.SchedulerFactoryBean" >		
  <property name="triggers">
    <list>
      <ref bean="keyGeneratorTrigger"/>
    </list>
  </property>
</bean>

JAVA 예제 소스

  • 위에서 JobClass로 지정한 com.oracleclub.web.job.KeyGeneratorJob 소스 입니다.
  • 아래 소스는 한 시간에 한번씩 암호화 키를 다시 생성하는 예제 입니다.
import java.util.ArrayList;
import java.util.List;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.springframework.scheduling.quartz.QuartzJobBean;

/**
 * Key Generator Job
 * 
 * @author : oramaster
 * 
 */
public class KeyGeneratorJob extends QuartzJobBean {
  private KeyPool keyPool;
  private final static Log LOG = LogFactory.getLog(KeyGeneratorJob.class);


  @Override
  protected void executeInternal(JobExecutionContext context) throws JobExecutionException {

    List<KeyGenerator> newList = new ArrayList<KeyGenerator>();
    KeyGenerator keyGenerator;

    try {
      //배치때 실행되는 비지니스 로직
      for (int i = 0; i < keyPool.getKeySize(); i++) {
        keyGenerator = new KeyGenerator();
        byte[] originKey = XORMask.getGeneratorKey();

        keyGenerator.setBlowFishKey(BlowFish.encrypt(originKey, BlowFish.getKey()));
        keyGenerator.setOriginKey(originKey);

        newList.add(keyGenerator);
      }

      keyPool.setKeyList(newList);

    } catch (Exception e) {
      LOG.error(e.getMessage());
      throw new JobExecutionException(e.getMessage());
    }
  }

  public void setKeyPool(KeyPool keyPool) {
    this.keyPool = keyPool;
  }
}

문서정보


===================================================================================


Chapter 19. Quartz 혹은 Timer 를 사용한 스케쥴링

19.1. 소개

Spring은 스케쥴링을 지원하는 통합 클래스들을 제공한다. 현재적으로, Spring은 1.3 이후버전 JDK의 일부분인 Timer와 Quartz 스케쥴러 (http://www.quartzscheduler.org)를 지원하고 있다. 이 두개의 스케쥴러들은 각각 Timer 혹은 Triggers에 대한 선택적 참조를 가지는 FactoryBean을 사용하여 세팅된다. 게다가 당신이 타겟 object의 메써드를 편리하게 호출할 수 있도록 도와주는 Quartz 스케쥴러와 Timer에 대한 편의 클래스를 제공한다.(이것은 일반적인 MethodInvokingFactoryBeans와 비슷하다.)

19.2. OpenSymphony Quartz 스케쥴러 사용하기

Quartz는 TriggersJobs 그리고 모든 종류의 jobs를 인식하고 있는 JobDetail를 사용한다. Quartz에 깔려 있는 기본적인 개념을 알고 싶다면, http://www.opensymphony.com/quartz를 찾아보길 바란다. 편리한 사용을 위해서, Spring은 Spring 기반 어플리케이션 내에서 Quartz의 사용을 손쉽게 만들어주는 두 개의 클래스들을 제공한다.

19.2.1. JobDetailBean 사용하기

JobDetail 객체는 job을 실행하기 위해 필요한 모든 정보를 가지고 있다. Spring은 소위 JobDetailBean이라고 불리는 클래스를 제공하는데, 이것은 JobDetail을 합리적인 디폴트값을 가진 실질적인 JavaBean 객체로 만들어준다. 다음의 예제를 보도록 하자.

<bean name="exampleJob" class="org.springframework.scheduling.quartz.JobDetailBean">
  <property name="jobClass">
    <value>example.ExampleJob</value>
  </property>
  <property name="jobDataAsMap">
    <map>
      <entry key="timeout"><value>5</value></entry>
    </map>
  </property>
</bean>
			

위의 job detail bean은 job(ExampleJob)을 실행하기 위한 모든 정보를 가지고 있다. 타임아웃은 job data map으로 기술되었다. job data map은 (실행시 넘겨지는) JobExecutionContext를 통해 이용할 수 있지만, JobDetailBean 역시 job data map으로부터 실질적인 job의 프라퍼티들을 매핑할 수 있다. 때문에 이러한 경우, 만약 ExampleJob이 timeout이라는 프라퍼티를 가지고 있다면, JobDetailBean은 그것을 자동으로 적용할 것이다.

package example;

public class ExampleJob extends QuartzJobBean {

  private int timeout;
  
  /**
   * Setter called after the ExampleJob is instantiated
   * with the value from the JobDetailBean (5)
   */ 
  public void setTimeout(int timeout) {
    this.timeout = timeout;
  }
  
  protected void executeInternal(JobExecutionContext ctx)
  throws JobExecutionException {
      // do the actual work
  }
}
			

당신은 job detail bean의 모든 부가적인 세팅들 역시 마찬가지로 이용할 수 있다.

주의: name과 group 프라퍼티를 사용함으로써, 당신은 job의 name과 group을 변경할 수 있다. default로 job의 이름은 job detail bean의 이름과 동일하다.(위의 예에서는 exampleJob이 된다.)

19.2.2. MethodInvokingJobDetailFactoryBean 사용하기

종종 당신은 특정한 객체의 메써드를 호출할 필요가 있을 것이다. 당신은 MethodInvokingJobDetailFactoryBean을 사용하여 다음과 같이 할 수 있다.

<bean id="methodInvokingJobDetail" 
  class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean">
    <property name="targetObject"><ref bean="exampleBusinessObject"/></property>
    <property name="targetMethod"><value>doIt</value></property>
</bean>

위의 예는 (아래에 있는) exampleBusinessObject의 doIt을 호출하는 것을 의미한다.

public class BusinessObject {
  
  // properties and collaborators
  
  public void doIt() {
    // do the actual work
  }
}
			

<bean id="exampleBusinessObject" class="examples.ExampleBusinessObject"/>
			

MethodInvokingJobDetailFactoryBean을 사용할 때, 메써드를 호출할 한줄짜리 jobs를 생성할 필요가 없으며, 당신은 단지 실질적인 비지니스 객체를 생성해서 그것을 묶기만 하면된다.

default로는 Quartz Jobs는 비상태이며, 상호 작용하는 jobs의 가능성을 가진다. 만약 당신이 동일한 JobDetail에 대해 두 개의 triggers를 명시한다면, 첫번째 job이 끝나기 이전에 두번째가 시작할지도 모른다. 만약 JobDetail 객체가 상태 인터페이스를 구현한다면, 이런 일은 발생하지 않을 것이다. 두번째 job은 첫번째가 끝나기 전에는 시작하지 않을 것이다. MethodInvokingJobDetailFactoryBean를 사용한 jobs가 동시작용하지 않도록 만들기 위해서는, concurrent 플래그를 false로 세팅해주어야 한다.

<bean id="methodInvokingJobDetail"
  class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean">
    <property name="targetObject"><ref bean="exampleBusinessObject"/></property>
    <property name="targetMethod"><value>doIt</value></property>
    <property name="concurrent"><value>false</value></property>
</bean>
			

주의: 기본적으로 jobs는 concurrent 옵션에 따라 실행될 것이다.

19.2.3. triggers 와 SchedulerFactoryBean을 사용하여 jobs를 묶기

우리는 job details과 jobs를 생성했고, 당신이 특정 객체의 메써드를 호출할 수 있도록 하는 편의클래스 bean을 살펴보았다. 물론, 우리는 여전히 jobs를 그자체로 스케쥴할 필요가 있다. 이것은 triggers와 SchedulerFactoryBean을 사용하여 이루어진다. 여러가지 triggers는 Quartz 내에서 이용할 수 있다. Spring은 편의를 위해 2개의 상속받은 triggers를 기본적으로 제공한다.:CronTriggerBean과 SimpleTriggerBean이 그것이다.

Triggers는 스케쥴될 필요가 있다. Spring은 triggers를 세팅하기 위한 프라퍼티들을 드러내는 SchedulerFactoryBean을 제공하고 있다. SchedulerFactoryBean은 그 triggers와 함께 실질적인 jobs를 스케쥴한다.

다음 두가지 예를 보자.

<bean id="simpleTrigger" class="org.springframework.scheduling.quartz.SimpleTriggerBean">
  <property name="jobDetail">
    <!-- see the example of method invoking job above -->    
    <ref bean="methodInvokingJobDetail"/>
  </property>
  <property name="startDelay">
    <!-- 10 seconds -->
    <value>10000</value>
  </property>
  <property name="repeatInterval">
    <!-- repeat every 50 seconds -->
    <value>50000</value>
  </property>
</bean>

<bean id="cronTrigger" class="org.springframework.scheduling.quartz.CronTriggerBean">
  <property name="jobDetail">
    <ref bean="exampleJob"/>
  </property>
  <property name="cronExpression">
    <!-- run every morning at 6 AM -->
    <value>0 0 6 * * ?</value>
  </property>
</bean>
			

OK, 이제 우리는 두 개의 triggers를 세팅했다. 하나는 10초 늦게 실행해서 매 50초마다 실행될 것이고, 다른 하나는 매일 아침 6시에 실행될 것이다. 모든 것을 완료하기 위해서, 우리는 SchedulerFactoryBean을 세팅해야 한다.

<bean class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
  <property name="triggers">
    <list>
      <ref local="cronTrigger"/>
      <ref local="simpleTrigger"/>
    </list>
  </property>
</bean>
			

당신이 세팅할 수 있는 더욱 많은 속성들이 SchedulerFactoryBean에 있다. 이를테면, job details에 의해 사용되는 calendars라던가, Quartz를 커스터마이징할 수 있게 하는 프라퍼티같은 것들이 말이다. 더 많은 정보를 위해서는 JavaDoc(http://www.springframework.org/docs/api/org/springframework/scheduling/quartz/SchedulerFactoryBean.html)을 참조하도록 해라.

19.3. JDK Timer support 사용하기

Spring에서 스케쥴링 업무를 처리하는 또다른 방법은 JDK Timer 객체들을 사용하는 것이다. Timers 자체에 대한 더 많은 정보는http://java.sun.com/docs/books/tutorial/essential/threads/timer.html에서 찾아볼 수 있다. 위에서 살펴 본 기본개념들은 Timer support에도 마찬가지로 적용된다. 당신은 임의의 timers를 생성하고 메써드들을 호출하기 위해 timer를 사용한다. TimerFactoryBean을 사용하여 timers를 묶는다.

19.3.1. 임의의 timers 생성하기

당신은 TimerTask를 사용하여 임의의 timer tasks를 생성할 수 있다. 이것은 Quartz jobs와 유사하다

public class CheckEmailAddresses extends TimerTask {

  private List emailAddresses;
  
  public void setEmailAddresses(List emailAddresses) {
    this.emailAddresses = emailAddresses;
  }
  
  public void run() {
    // iterate over all email addresses and archive them
  }
}
			

이것을 묶는 것 역시 간단하다:

<bean id="checkEmail" class="examples.CheckEmailAddress">
  <property name="emailAddresses">
    <list>
      <value>test@springframework.org</value>
      <value>foo@bar.com</value>
      <value>john@doe.net</value>
    </list>
  </property>
</bean>

<bean id="scheduledTask" class="org.springframework.scheduling.timer.ScheduledTimerTask">
  <!-- wait 10 seconds before starting repeated execution -->
  <property name="delay">
    <value>10000</value>
  </property>
  <!-- run every 50 seconds -->
  <property name="period">
    <value>50000</value>
  </property>
  <property name="timerTask">
    <ref local="checkEmail"/>
  </property>
</bean>
			

task를 단지 한번만 실행하고자 한다면, period 속성을 -1(혹은 다른 음수값으)로 바꿔주면 된다.

19.3.2. MethodInvokingTimerTaskFactoryBean 사용하기

Quartz support와 비슷하게, Timer 역시 당신이 주기적으로 메써드를 호출할 수 있도록 하는 요소들을 기술한다.

<bean id="methodInvokingTask" 
  class="org.springframework.scheduling.timer.MethodInvokingTimerTaskFactoryBean">
    <property name="targetObject"><ref bean="exampleBusinessObject"/></property>
    <property name="targetMethod"><value>doIt</value></property>
</bean>

위의 예제는 (아래와 같은) exampleBusinessObject에서 호출되는 doIt에서 끝날 것이다

public class BusinessObject {
  
  // properties and collaborators
  
  public void doIt() {
    // do the actual work
  }
}
			

ScheduledTimerTask가 언급된 위의 예제의 참조값을 methodInvokingTask로 변경하면 이 task가 실행될 것이다.

19.3.3. 감싸기 : TimerFactoryBean을 사용하여 tasks를 세팅하기

TimerFactoryBean은 실질적인 스케쥴링을 세팅한다는 같은 목적을 제공한다는 점에서 Quartz의 SchedulerFactoryBean과 비슷하다. TimerFactoryBean는 실질적인 Timer를 세팅하고 그것이 참조하고 있는 tasks를 스케쥴한다. 당신은 대몬 쓰레드를 사용할 것인지 말것인지를 기술할 수 있다.

<bean id="timerFactory" class="org.springframework.scheduling.timer.TimerFactoryBean">
  <property name="scheduledTimerTasks">
    <list>
      <!-- see the example above -->
      <ref local="scheduledTask"/>
    </list>
  </property>
</bean>
			

끝!


출처 - http://openframework.or.kr/framework_reference/spring/ver1.2.2/html/scheduling.html













 

 

 

 

 

 

 

 

 

Posted by linuxism
,


01 01 * * * /usr/java/j2sdk1.3.1_02/bin/java -Dfile.encoding=8859_1 -classpath /usr/local/sms/sender sms.SMSmanager

위 내용이 입력한 crontab 내용이다. (매일 새벽 1시 1분에 자바크래스를 실행한다)

시스템상에 path랑 claspath를 잡아 뒀더래도 crontab에서는 인식하지 않는다..
그래서 java명령에 PATH를 포함하였고 -classpath 옵션을 주었다.

또한 팀으로 -Dfile.encoding= 옵션으로 인코딩을 지정해줘야 한다. 크론탭으로 실행될때는 한글이 깨지는 상황이 발생하기 때문.

crontab -l : cron정의 내용리스트보기
crontab -e : vi로 cron 정의내용 수정하기
crontab -r : cron 삭제하기

분(0-59)시(0-23)일(1-31)월(1-12)일(0-7) 


출처 - http://javagomtang.tistory.com/archive/200811http://www.okjsp.pe.kr/seq/31301


===================================================================================


Cron으로 자바프로그램 수행하기
 
1. 자바 프로그램 예제
 
  다음과 같이 현재 시간을 출력하는 자바 프로그램을 Cron을 이용하여 주기적으로 수행 되도록하겠습니다.
 

 

  import java.util.*;
 
  public class CurrentTime
  {
    static public void main(String[] args)
    {
       System.out.println("Current Time is " + new Date());
    }
  }
 

 

 

2. 컴파일
  예제 자바 프로그램을 컴파일 합니다.
 

 

 $> javac CurrentTime.java

 

 
 
3. crontab 파일 작성
  등록된 스크립트나 프로그램은 Cron 데몬에 의하여 수행되므로 결과를 출력할 수 없습니다. 이번 예제에서는 실행 시 출력을 /root/cron.log 파일로 저장하도록 합니다.
아래 예제는 매초마다 수행하도록 설정하였습니다. crontab 구문은 크게 스케줄링 필들들과 명령행으로 구성됩니다.
 
  java 실행 문 앞의 "* * * * *" 스케줄을 나타냅니다. 앞에서 부터 분,시,일,월,요일에 대한 스케줄을 나타냅니다.
 

 각 필드는 공백으로 구분됩니다. 스케줄링 필드들에서 *는 매분, 매시, 매일,... 등의 의미입니다. 설정하는 값은 ","를 이용하여 여러개를 입력할 수 있습니다.

 

 필드

 대상

설정 가능한 값

필드1

0 - 59, *

   

필드2

0 - 23, *

필드3

1 - 12, *

필드4

1 - 31, *

필드5

요일

0 - 6 (0=sunday), *

 

예제)

 

  5 * * * *    : 5초에 수행합니다.
  0 1 1 * *    : 매달 1일 1시 정각에 수행합니다.
  5,10,15 * * * * : 매월 매일 매시 5분, 10분 15분에 수행합니다.
  0 1,15 * 1  : 매달의 월요일들뿐만 아니라 1일과 15일에 수행합니다.
  30 6 * * 1,3,5 : 매달 월요일, 수요일, 금요일 오전 6시 30분에 수행합니다.

 

 

$> vi crontab.cron
* * * * * /usr/local/java/bin/java -classpath "/root" CurrentTime > /root/cron.log
 

 

  등록된 스크립트 및 프로그램은 등록한 사용자의 사용자 HOME 디렉터리에서 실행되지만 ".profile"을 수행하지않습니다. 따라서 사용자가 ".profile"에 정의한 PATH, CLASSPATH등이 환경변수에 적용되지않으므로 java 실행 파일 경로를 Full-Path로 하였습니다.  또다른 방법은 쉘 스크립트로 만들고 이 스크립트에서 ".profile" 로드하거나 직접 쉘 스크립트에서 환경 변수를 명령을 문 이전에 설정해도 됩니다. 
 

 

$> vi crontab.cron

 * * * * * currenttime.sh > /root/cron.log
  
$> vi currenttime.sh
 
PATH=$PATH:/usr/local/java/bin; export PATH    
CLASSPATH=$CLASSPATH:/root; export CLASSPATH 
java CurrentTime > /root/cron.log
 

 

or
 

 
$> vi currenttime.sh
 
. .profile
java CurrentTime > /root/cron.log
 
$> chmod 777 currenttime.sh
 

 

4. crontab 파일 등록
 

 

$> crontab crontab.cron

 

 

 
5. crontab 등록확인
 

 

$> crontab -l
    # DO NOT EDIT THIS FILE - edit the master and reinstall.
    # (crontab.cron installed on Thu Dec  9 14:23:43 2004)
    # (Cron version -- $Id: crontab.c,v 2.13 1994/01/17 03:20:37 vixie Exp $)
    * * * * * /usr/local/java/bin/java -classpath "/root"

                                 CurrentTime> /root/cron.log

 

   

6. crontab 실행 결과 확인
 

 

   $> vi /root/cron.log
   Current Time is Thu Dec 09 14:38:00 KST 2004
 



===================================================================================

안녕하세요 이번에 자바로 소켓데몬을 하나만들었는데요.

 

유닉스에서 크론텝에 등록시켜서 사용할라고 하는데 자바가 실행이 안되고..

 

sh파일을 바로 기동시키면 돌아가고. 크론텝에 등록된건 안되고해서 현재 손수 기동시켜주고있습니다.;;

 

0,5,10,15,20,25,30,35,40,45,50,55 * * * * /ktfinterface/ktfpps3g/script/act3gboot.sh

 

크론텝 안에 내용이구요..

 

sh파일 내용은..

 

#!/bin/ksh
#--------------------------------------
# 사용자 LIB PATH 설정
# System LIB PATH 설정
LIB_CLASS=/oracle/app/oracle/product/10.2.0/jdbc/lib/classes12.jar
MAIN_PGM=/ktfinterface/ktfpps3g/bin/ib3ginf_deploy.jar

#**************************************
# 사용되는 LIB LINK 설정
LINK_CLASS=$LIB_CLASS:$MAIN_PGM
#--------------------------------------
MPGMNM=rms3gact
RUNPGM=act.rms3gact
#--------------------------------------

####################### rms3gact ##########################
check=`ps -ef|grep "svc.startd" | grep -v grep |awk !/grep/`
#
check=`ps -ef|grep "rms3gact" | grep -v grep | wc -w`
if [ $check == 0 ];then
  echo '---'
  echo '------------------------------------------------'
  echo '|                                              |'
  echo '|       rms3gact 기동(RMS)                     |'
  echo '|                                              |'
  echo '------------------------------------------------'
  java -D$MPGMNM -classpath $LINK_CLASS $RUNPGM $MPGMNM &

  echo ' 기동 완료 '
fi
echo 'endend'
#==============================================================

 

요로콤 해놨습니다.   여기저기 검색해보니 자바는 환경을 따로잡아야된다고해서 여러가지  시도를 해봤는데.

 

몬하는건지 안되는건지 ㅜ.ㅜ

 

그럼  많은 지식 부탁드리겠습니다.

 

// =======================================================================

#!/bin/sh

 

# PATH 설정
PATH=.:(경로)/jdk1.5.0_05/bin/:$PATH
export PATH

 

# CLASSPATH 설정
CLASSPATH=.:(경로)/jdk1.5.0_05/lib/tools.jar:
export CLASSPATH

 

# 실행파일 Directory 이동
cd (경로)/bin

 

# 현재날짜
DATE=`date '+%Y%m%d'`

 

# 프로그램 실행

java XXXXX >> (경로)/log/$DATE.log

 

// =======================================================================

 

위에 까지가 현재 제가 사용하고 있는 crontab 에 등록하여 java를 실행시키는 쉘 명령어 입니다.

 

위에 처럼 자바의 환경을 잡아 준뒤에 실행해 보시면 정상적으로 작동을 할 것 입니다.

 

제가 사용하는 서버는 솔라리스와 HP 서버 두군데를 사용하고 있는데 정상적으로

 

crontab에서 실행하고 있습니다.

 

 

===================================================================================

 

수동으로 실행하면되고 크론탭에서 안되는 근본 이유는 아마도

수동으로 실행하시는 계정의 .profile에 설정된 각종 환경변수 셋팅이 crontab으로 실행시에는 없기 때문입니다

따라서 crontab에서 실행하는 /ktfinterface/ktfpps3g/script/act3gboot.sh 파일 상단에

 

#!/bin/ksh

계정홈디렉토리/.profile

 

추가하시면 crontab에서도 실행될겁니다







'Development > Java' 카테고리의 다른 글

java - 현재 시간 확인  (0) 2012.07.18
java - java.lang.NullPointerException 에러  (1) 2012.05.24
java - ORM  (0) 2012.05.15
JNDI(Java Naming and Directory Interface)  (0) 2012.05.10
java - thread example  (0) 2012.05.05
Posted by linuxism
,


스프링은 굉장히 크고 방대한 프레임웍입니다. 

여기서 다루는 내용은 스프링을 처음 시작할 때 참고할 만한 내용들로 구성한 '스프링 겉핥기' 수준입니다. 

스프링에 대해 본격적으로 배우기 위해서는 각각의 주제들에 대해 좀더 상세히 다루고 있는 서적이나 웹 문서 등을 활용하시기 바랍니다.

학습이나 업무 중에 궁금하신 내용들이 있으시면, KSUG 그룹스 메일링이나 페이스북 그룹 등을 활용하시면 도움이 될 것입니다.

스프링의 세계에 오신 것을 환영합니다~! 건승을 빕니다~!

(아래서 참조한 스프링 레퍼런스 원문에 대한 번역 본들은  http://blog.outsider.ne.kr/tag/spring_reference_documentation 에서도 찾아볼 수 있습니다.)


1. 스프링이란 무엇인가?

개요/소개

http://static.springsource.org/spring/docs/3.1.x/spring-framework-reference/html/spring-introduction.html

The Spring Framework is a lightweight solution and a potential one-stop-shop for building your enterprise-ready applications.

스프링 프레임웍은 엔터프라이즈급 애플리케이션을 만들기 위한 모든 기능을 종합적으로 제공하는 경량화된 솔루션이다.

- Note : 엔터프라이즈급 애플리케이션

  단일 데스크탑에서 실행되는 J2SE(Standard Edition)기반의 애플리케이션과는 대조적으로, 네트워크를 기반으로 여러 컴퓨터와 관계해서 실행되는 규모가 큰 J2EE(Java2 Enterprise Edition) 기반의 애플리케이션. 대표적으로 웹 서비스.

- Note : 모든 기능을 종합적으로 제공하는

  엔터프라이즈 애플리케이션을 개발할 때 반복적으로 등장하는 웹 요청 처리, JDBC/트랜잭션, 리모팅/인티그레이션 등에 대한 솔루션을 스프링 프레임웍을 통해 대부분 제공할 수 있게 함. 

- Note : 경량화된 솔루션

  상대적으로 무거운 EJB에 대한 대안으로 고안된 POJO 기반의 경량 빈 팩토리/컨테이너. 


http://static.springsource.org/spring/docs/3.1.x/spring-framework-reference/html/overview.html

Spring Framework is a Java platform that provides comprehensive infrastructure support for developing Java applications. Spring handles the infrastructure so you can focus on your application.

스프링 프레임웍은 자바 애플리케이션을 개발하기 위해 필요한 인프라스트럭처를 종합적으로 제공해, 개발자로 하여금 애플리케이션 개발에 집중할 수 있게 도와준다.

- Note : 인프라스트럭처

  (유사: boilerplate code, 배관(?) 코드) 

  애플리케이션에서 문제해결을 위한 주요 관심 코드가 아닌, 주변적이면서도 반드시 있어야 하는 공공재(?) 적인 코드들. 반드시 필요하지만 번거롭게 반복적으로 등장하기 때문에, 코드 재사용을 위한 첫번째 해결 목표가 된다.

Spring enables you to build applications from “plain old Java objects” (POJOs) and to apply enterprise services non-invasively to POJOs. This capability applies to the Java SE programming model and to full and partial Java EE.

스프링은 POJOs(plain old java objects)를 기반으로 애플리케이션을 개발할 수 있게 하여, 엔터프라이즈 서비스를 비간섭적(non-invasively)으로 POJO에 적용시킬 수 있게 해준다. 이러한 기술은 자바SE 프로그래밍 모델뿐만 아니라 전체 또는 일부의 자바EE에 까지 적용할 수 있게 된다. 

- Note : POJO(Plain Old Java Object)

  보통의 자바 (빈) 객체

- Note : 비간섭적(non-invasively)

  간섭적(invasively)인 코드와 대조적인 개념으로, 상속이나 의존관계에 의해 코드 작성에 제약사항을 가하게 되는 코드를 배제한다는 개념.

IoC

http://static.springsource.org/spring/docs/3.1.x/spring-framework-reference/html/overview.html#overview-dependency-injection


IoC(Inversion of Control)는 스프링 프레임웍의 핵심이 되는 개념이자 기술입니다. 관련된 문서나 서적(스프링의 핵심 개념들을 제대로 배우고 싶으시면 토비의 스프링3를 추천합니다. ^^;) 을 통해 반드시 이해할 필요가 있습니다. 처음부터 이해하기 어려운 경우에는, 구현 예제를 통해 스프링을 우선 사용해본 뒤 나중에라도 반드시 이해할 수 있도록 합니다.

- Spring IoC 개념 및 활용방안

http://www.javajigi.net/pages/viewpage.action?pageId=5614

- 토비의 스프링, 2부 선택 - 10장 IoC 컨테이너와 DI

http://code.google.com/p/developerhaus/wiki/TobySpring_10

스프링, 먹는건가?

그러니까,, 스프링 프레임웍(이하, 스프링)이라는 것은 자바+웹 개발자라고 하면 반드시 직면하게 되는 개발문제들에 대해, 아주 훌륭하고 유연한 설계를 통해 개발 Best Practice(모범사례)들을 제공해주고, 비슷한 처지의 개발자들이 매번 똑같은 코드를 재생산하게 되는 것을 방지해주는 아주 유익한(!) 솔루션이다... 라고 말할 수 있겠습니다.

(어디까지나 작성자의 사견이며 공식적인 정의는 아니므로,, 참고만 하세요.. 태클은 사양하겠습니다. __;;)

2. 스프링은 어떻게 구성되어 있는가?

모듈 구성

http://static.springsource.org/spring/docs/3.1.x/spring-framework-reference/html/overview.html#overview-modules


1. Core Container

Core Container는 Core, Beans, Context, EL(Expression Language) 모듈들로 구성되어 있다.

Core 모듈과 Beans 모듈은 프레임웍의 기반이 되는 부분들로, IoC와 DI(Dependency Injection, 의존성주입) 기능을 제공한다. BeanFactory는 팩토리 패턴을 철학적으로 구현해놓은 것으로, 프로그램에서 직접 싱글톤을 생성하지 않을 수 있게 해주며, 객체간의 의존관계를 실제 프로그램 로직에서부터 설정파일로 분리해낼 수 있게 해준다.

Context 모듈은 Core 모듈과 Beans 모듈의 실체화된 부분을 제공하며, 객체에 대한 접근 방법을 JNDI 레지스트리와 유사하게 프레임웍 형식으로 제공한다. Context 모듈은 Beans 모듈의 기능을 상속받고, 이에 추가적으로 국제화(리소스 번들의 사용과 같은), 이벤트 전이(event-propagation), 리소스 로딩, 서블릿 컨테이너와 같은 컨텍스트의 생성 기능들을 함께 제공한다. 

Expression Language 모듈은 객체 그래프를 런타임시에 조회하고 조작할 수 있는 강력한 표현 언어 기능을 제공하며, JSP 2.1 스펙에서 사용하는 통합표현언어(unified EL)를 확장하고 있다. 


2. Data Access/Integration

Data Access/Integration 레이어는 JDBC, ORM, OXM, JMS, 트랜잭션 모듈들로 구성되어 있다.

JDBC 모듈은 JDBC-추상 레이어를 제공하여 데이터베이스의 종류에 따른 JDBC 구현코드와 에러 코드를 대신 다루어준다.

ORM 모듈은 JPA, JDO, 하이버네이트(Hibernate), iBatis와 같이 잘 알려진 객체-관계매핑(object-relational mapping, ORM) API들에 대한 인티그레이션 레이어를 제공한다. 

OXM 모듈은 JAXB, Castor, XMLBeans, JiBX, XStream과 같은 객체/XML 매핑(Object/XML mapping) 구현체에 대한 추상 레이어를 제공한다.

JMS(Java Messaging Service) 모듈은 메시지의 생성과 소비 기능을 제공하며, Transaction 모듈은 프로그램적(programmatic) 또는 선언적(declarative) 트랜잭션 관리 기능을 제공한다. 


3. Web

웹 레이어는 Web, Web-Servlet, Web-Struts, Web-Portlet 모듈들로 구성되어 있다.

스프링의 Web 모듈은 multipart 파일업로드, 서블릿 리스너를 사용한 IoC 컨테이너와 웹-애플리케이션 컨텍스트를 초기화 등의 기본적인 웹 관련 인티그레이션 기능들을 제공한다.

Web-Servlet 모듈은 웹 애플리케이션에 필요한 스프링의 MVC(model-view-controller) 구현체를 제공한다. 


4. AOP and Instrumentation

스프링의 AOP 모듈은 AOP Alliance의 규약에 호환되는 관점-지향 프로그래밍(aspect-oriented programming) 구현체를 제공하며, 메서드 인터셉터와 포인트컷을 사용해 코드를 기능별로 깔끔하게 분리될 수 있게 도와준다. 

Aspects 모듈은 AspectJ와의 인티그레이션을 제공하며, Instrumentation 모듈은 특정 애플리케이션 서버에서 사용되는 클래스로더(classloader) 구현체와 인스트루먼테이션(instrumentation) 기능을 제공한다.


5. Test

Test 모듈은 JUnit 또는 TestNG를 사용해 테스트를 지원하는 스프링 컴포넌트를 제공한다. 


사용 시나리오

http://static.springsource.org/spring/docs/3.1.x/spring-framework-reference/html/overview.html#overview-usagescenarios 

스프링의 모듈들을 활용해 여러 가지 형태의 시나리오에 따라 블럭을 구성할 수 있으며, 몇 가지 예를 들면 다음과 같다.


1. 일반적인 사용 시나리오 (웹 애플리케이션)

핵심 도메인들은 Core Container 기능들을 활용해 커스텀 도메인 로직으로 구성하고,

하위에서는 AOP를 활용해 POJO에 대해 선언적 트랜잭션으로 구성하고, ORM 매핑 구현체를 적용해 커스텀 DAO/레파지토리를 구성할 수 있다.

상위에서는 폼 컨트롤러를 두어 일반적인 웹 요청을 처리하고, 파일업로드 등에 대한 Multipart 리졸버와 요청 파라미터에 대한 동적 바인딩을 활용할 수 있다. 결과 뷰에 대해서도 JSP, Velocity, PDF, 엑셀 등 여러 가지 인티그레이션을 활용할 수 있다.

그리고, 외부 시스템과의 연동을 위해 여러 가지 리모팅/인티그레이션 기술들을 활용할 수 있다.


2. 외부 프론트 웹 프레임웍을 사용하는 시나리오

미들단 하위로는 스프링의 모듈들을 사용하며, 웹 요청/처리단 만을 스프링 MVC 대신 Struts 등의 외부 프론트 웹 프레임웍을 인티그레이션하는 형태


3. 리모팅 웹 서비스 API 구현 시나리오

리모팅 웹 서비스 API 구현을 위해 웹 요청/처리 단을 스프링의 Hessian, Burlap, Rmi 등의 구현체를 사용한 형태 


3. 스프링을 사용하는 방법

Java HelloWorld


Web HelloWorld


4. 스프링에 대해 더 배우기

공식문서

학습도서

(yes24 선정 기준 1~5위)

- 토비의 스프링3

http://www.yes24.com/24/goods/4020006

- 스프링 인 액션

http://www.yes24.com/24/goods/6229706

- 스프링3 레시피

http://www.yes24.com/24/goods/4744444

- 웹 개발자를 위한 스프링 3.0 프레임워크

http://www.yes24.com/24/goods/3945627

- 스프링 프레임워크 3.0

http://www.yes24.com/24/goods/6230929


(용감하신 분은 원서도 추천...!)

블로그/링크




출처 - http://www.ksug.org/search/aop










Posted by linuxism
,