Spring + Quartz 주기적으로 작업 실행하기

프로그래밍/스프링프레임워크 2018. 4. 20. 23:03
반응형

SpringFramework 4.3.4 버전에서 Quartz 2.3.0 라이브러리를 사용해서 주기적으로 작업을 실행하는 방법을 알아보겠습니다. 전체 소스는 하단에 첨부해 두었습니다. 앞에서 계속 사용해오던 소스라 DB 연결, 엑셀 다운로드 등의 소스가 같이 있는데 필요 없는 부분은 주석처리하고 테스트 해보시면 되겠습니다.



1. pom.xml 파일에 quartz 라이브러리의 의존성을 추가합니다.


<!-- quartz 라이브러러리 -->

<dependency>

    <groupId>org.quartz-scheduler</groupId>

    <artifactId>quartz</artifactId>

    <version>2.3.0</version>

</dependency>


<!-- 스프링 Quartz 도우미 라이브러리 -->

<dependency>

    <groupId>org.springframework</groupId>

    <artifactId>spring-context-support</artifactId>

    <version>4.3.4.RELEASE</version>

</dependency>



2. 주기적으로 실행될 서비스 메소드를 생성합니다.

com.tistory.pentode.service.BoardService.java파일에 메소드 인터페이스를 추가합니다.


void testJobMethod();


com.tistroy.pentode.service.impl.BoardServiceImpl.java 파일에 구현 메소드를 추가합니다.


...

@Service("boardService")

public class BoardServiceImpl implements BoardService {

   ...

   @Override

    public void testJobMethod() {

    System.out.println("test job....");

    }

   ...

}



3. root-context.xml 파일에 스케줄러 설정을 추가합니다.


위에서 작성한 서비스 객체의  testJobMethod() 메소드가 주기적으로 실행되도록 설정합니다.


<!-- 테스트용 잡  -->

<bean id="testJob" class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean">

    <!-- 서비스 구현 객체의 빈 이름을 인자로 줍니다. -->

    <property name="targetObject" ref="boardService" />

    <!-- 서비스 객체에서 주기적으로 실행될 메소드른 지정합니다. -->

    <property name="targetMethod" value="testJobMethod" />

    <!-- 동시 실행을 방지합니다. -->

    <property name="concurrent" value="false" />

</bean>


<!-- 테스트용  트리거-->

<bean id="testJobTrigger" class="org.springframework.scheduling.quartz.CronTriggerFactoryBean">

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

    <!-- CronTrigger를 사용하여 2분 간격으로 실행되도록 지정했습니다. -->

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

</bean>


<!-- 테스트용 스케줄러 -->

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

    <property name="triggers">

        <!-- 앞에서 설정한 트리거를 등록합니다. 필요하면 여러개 만들어서 등록하면 됩니다. -->

        <list><ref bean="testJobTrigger" /></list>

    </property>

</bean>



4. 실행결과 입니다.





5. Quartz에서 작업을 스케쥴하는데 SimpleTrigger와  CronTrigger 를 사용할 수 있습니다.


5.1 SimpleTrigger - 간단하게 특정 시간 간격으로 작업을 실행합니다.


<!-- 테스트용  트리거-->

<bean id="testJobTrigger" class="org.springframework.scheduling.quartz.SimpleTriggerFactoryBean">

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

    <!-- 시작하고 1분후에 실행한다. (milisecond) -->

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

    <!-- 매 24시간마다 실행한다.864000000 (milisecond) -->

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

</bean>



5.2 유닉스 크론 처럼 스케쥴할 수 있습니다.


<!-- 테스트용  트리거-->

<bean id="testJobTrigger" class="org.springframework.scheduling.quartz.CronTriggerFactoryBean">

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

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

</bean>


- Cron Expression에는 총 7개의 필드 있고 마지막 필드(년도)는 생략 가능합니다.


필드이름 허용 값
초(Seconds) 0 ~ 59
분(Minutes) 0 ~ 59
시간(Hours) 0 ~ 23
일(Day-of-month) 1 ~ 31
달(Months) 1 ~ 12 or JAN ~ DEC
요일(Day-of-week) 1 ~ 7 or SUN-SAT
년도(Year)(생략가능) 1970 ~ 2099


- Cron Expression의 특수문자


Expr 설명
* 모든 수를 나타냅니다.
- 값의 사이를 의미합니다. "* 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 필드만 사용). 일 필드에 사용되면 이달의 마지막일을 나타냅니다. L-3 은 이달의 마지막날 3일 전부터 마지막날까지를 나타냅니다. 요일 필드에 사용되면 토요일(7 or SAT)을 나타냅니다. 6L or FRIL 은 이달의 마지막 금요일을 나타냅니다.
W 주어진 날로부터 가장 가까운 평일(월 - 금)을 나타냅니다. 15W 를 일 필드에 사용하면 이달의 15번째 날에서 가장 가까운 평일을 나타냅니다.
# 이달의 n번째 x 요일 을 나타냅니다. 6#3 or FRI#3 은 이달의 세번째 금요일을 나타냅니다.


- Cron 표현식 예제


* 매 2분 마다 실행 : "0 0/2 * ?"

* 10초뒤 2분마다 실행 : "10 0/2 * ?"

* 매일 오전 1시에 실행 : "0 0 1 * * ?"

* 매주 금요일 오전 1시에 실행 : "0 0 1 ? * FRI"

* 매주 수요일과 금요일 10:30, 11:30, 12:30, 13:30 에 실행 : "0 30 10-13 ? * WED,FRI"

* 매월 5일, 20일 오전 8시부터 오전 10시 사이에 30분 간격으로 실행 : "0 0/30 8-9 5,20 * ?"



6. 실제로 Tomcat 으로 배포했을때 quartz job이 두 번 반복 실행되는 경우가 발생했었습니다.

여기 저기 검색해 본 결과 다음 글에서 원인을 알 수 있었습니다. "http://blog.ajkuhn.com/116"


Tomcat 설정파일의 <Host> 태그의 appBase 와 <Host> 태그에 포함되는 <Context> 태그의 docBase 를 설정할 때 appBase하위폴더로 docBase 를 지정하게 되면 컨텍스트가 두 번 생성되고, 스케줄이 두 번 실행되는 것이었습니다.  값을 다른 곳으로 지정하여 해결했습니다.


이것으로 SpringFrmework에서 quartz 라이브러리를 사용하여 주기적인 작업을 수행하는 방법을 알아 보았습니다.


※ 예제소스

spring_quartz.zip


반응형

댓글을 달아 주세요

  • 남기성 2019.10.29 16:04  댓글주소  수정/삭제  댓글쓰기

    질문있습니다~
    쿼츠 처음 서볼라하는데 하나가막히네요....
    root.xml은 어디있나요?
    답 주시면 감사하겠 습니다~

    • pentode 2019.10.29 19:10 신고  댓글주소  수정/삭제

      안녕하세요. 글 내용에 오류가 있었네요. 쿼츠 설정이 있는 파일은 root-context.xml 파일 입니다. 예제 소스를 다운로드 받으면 src/main/webapp/WEB-INF/spring/root-context.xml 파일 입니다.

      본문을 수정을 했습니다. 감사합니다.^^

  • 남기성 2019.10.29 20:49  댓글주소  수정/삭제  댓글쓰기

    답글 감사합니다~^^

  • 남기성 2019.10.29 21:18  댓글주소  수정/삭제  댓글쓰기

    감사합니다...
    성공했어요~~
    복받으실거여요~~ㅋㅋ

  • 롬봇 2019.11.13 14:25  댓글주소  수정/삭제  댓글쓰기

    똑같이 따라했는데 어노테이션 오류
    Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)} 가 떠요 ㅠㅠ

    • pentode 2019.11.13 21:19 신고  댓글주소  수정/삭제

      Autowired로 불러오는 빈이 존재하지 않거나 @Repository 또는 @Service로 지정되지 않았거나, 지정된 이름에 오타가 났거나 하는 문제가 아닐까 생각 되네요. 예제 소스에는 @Autowired 가 사용된 곳이 아래와 같이 있습니다.

      @Autowired
      private SqlSessionFactory sqlSessionFactory;

      이 빈은 root-context.xml 파일에 설정되어 있습니다.

      위의 경우들을 확인해 보세요.

  • 자바 2020.04.09 10:37  댓글주소  수정/삭제  댓글쓰기

    안녕하세요

    위에 프로젝트는 어떻게 생성를 해야하는지요

    • pentode 2020.04.12 23:05 신고  댓글주소  수정/삭제

      안녕하세요. 이 예제는 일반적인 스프링 웹 프로젝트에 적용할 수 있습니다. 첨부된 소스 파일은 Eclipse에서 작성된 파일 입니다. Eclipse에서 import 하시면 됩니다.

      제 블로그를 검색해 보시면 Eclipse에서 spring 웹 프로젝트를 만드는 다양한 방법이 있습니다. 참고하시면 될것 같습니다.

      방문해 주셔서 감사합니다.^^