[Java] JSP Spring framework 환경에서 scheduler의 cron 사용법


Development note/Java  2020. 1. 16. 09:00

안녕하세요. 명월입니다.


이 글은 JSP Spring 환경에서 scheduler의 cron을 사용하는 방법에 대한 글입니다.


이전에 제가 JSP환경에서 spring web framework를 이용해서 웹 환경을 구축하는 방법에 대해 설명한 적이 있습니다.

링크 - [Java강좌 - 41] eclipse에서 spring web framework를 이용해서 웹 서비스 프로젝트를 만드는 방법


먼저 cron이라는 것은 간단히 이야기하면 스케줄러라고 생각하면 됩니다. 이전에 unix시절에 사용되던 scheduler의 유틸리티 이름인데, 이게 linux로 넘어오면서 cron 스케줄러로 남아있다가 java계열의 스케줄러 이름도 cron으로 넘어 온 것같습니다.

스케줄러라는 것은 os 운영체제에서 운영하는 것이 여러모로 서버를 관리하기 편합니다만, 스케줄러의 특성에 따라서 웹서비스 안에서 처리하는 경우도 많이 있기 때문에 spring 웹 서비스에서도 사용되기도 합니다.


웹 서비스에서 사용되는 스케줄러라고 하면, 기본적으로 서비스 내에서 생성되는 필요없는 log데이터 삭제던가, 게시판 서비스라고 하면 글 올리기 예약시스템, 사양에 따른 데이터 베이스 정리등등 여러가지 작업을 예상할 수 있습니다.

그런데 os환경에서 사용되는 스케줄러와 웹 서비스내에서 사용되는 스케줄러를 분명히 구분해야 하는 이유는 예를 들면 로드벨런싱(분산시스템)으로 나누어지는 2대 이상의 웹서비스가 가동되는 대형 포털이라고 가정할 때, 각 웹 서버에서는 cron 잡 스케줄러가 각기 실행 중이기 때문에 데이터 베이스 중복 처리가 발생하는 경우도 있습니다.

이럴 때는 웹 서비스의 스케줄러가 아닌 별도의 스케줄러의 서버를 구축 후에 os 스케줄러나 db의 스케줄러로 처리하는 게 맞습니다.(이게 은근히 이런 실수가 많습니다.)


웹 서비스 내에 사용되는 스케줄러는 로드벨런싱이 없는 단일 시스템이라고 하면 어떤 처리를 넣어도 상관이 없지만, 보통은 캐쉬나 세션, 임시 temp 파일, 로그 파일(사실 로그도 os측의 스케줄러로 관리하는 게 편합니다.)등을 관리하는 게 보통입니다.


그럼 spring환경에서 cron을 설정하는 방법에 대해 설명하겠습니다.

먼저 pom.xml에 두개의 라이브러리를 등록합니다.

레포지토리 - https://mvnrepository.com/artifact/org.quartz-scheduler/quartz

레포지토리 - https://mvnrepository.com/artifact/org.quartz-scheduler/quartz-jobs

<!-- https://mvnrepository.com/artifact/org.quartz-scheduler/quartz -->
<dependency>
  <groupId>org.quartz-scheduler</groupId>
  <artifactId>quartz</artifactId>
  <version>2.3.2</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.quartz-scheduler/quartz-jobs -->
<dependency>
  <groupId>org.quartz-scheduler</groupId>
  <artifactId>quartz-jobs</artifactId>
  <version>2.3.2</version>
</dependency>

그리고 spring mvc config파일을 수정합니다.


task 스키마를 추가하고 driven을 추가 설정하면 됩니다.

<?xml version="1.0" encoding="UTF-8"?>
<!-- cron을 사용하기 위해서 xmlns:task를 추가하고 xsi:schemaLocation에도 task 스키마 url를 추가합니다. -->
<beans xmlns="http://www.springframework.org/schema/beans" 
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:mvc="http://www.springframework.org/schema/mvc" 
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:task="http://www.springframework.org/schema/task"
       xsi:schemaLocation="http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd
                           http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
                           http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
                           http://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring-task.xsd">
	<context:component-scan base-package="controller"/>
	<mvc:annotation-driven>
		<mvc:message-converters>
			<bean class="org.springframework.http.converter.StringHttpMessageConverter">
				<property name="supportedMediaTypes">
					<list>
						<value>text/html;charset=UTF-8</value>
					</list>
				</property>
			</bean>
		</mvc:message-converters>
	</mvc:annotation-driven>
	<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
		<property name="prefix" value="/WEB-INF/view/"/>
		<property name="suffix" value=".jsp"/>
	</bean>
    <!-- driven을 추가합니다. base-package는 위 context driven처럼 cron 클래스를 검색 실행하기 위한 패키지를 입력합니다. -->
	<context:component-scan base-package="controller.cron"></context:component-scan>
	<task:annotation-driven />
</beans>

저의 경우는 controller.cron 패키지를 설정했습니다.

controller.cron 패키지에 Scheduler클래스를 추가했습니다.

package controller.cron;

import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

// cron 스케줄러 클래스임을 선언하는 어노테이션.
@Component
public class Scheduler {
  // cron 문법으로 스케줄러가 실행되는 주기를 설정.(아래의 cron 스케줄 문법에 자세한 설명)
  @Scheduled(cron = "* * * * * *")
  public void run() {
    System.out.println("cron test!!");
  }
}

위 cron은 매초 실행하는 형식의 cron 잡 스케줄러를 설정했습니다.

웹 서비스를 실행하기 되면 cron 스케줄러가 실행되어 run함수가 매초에 한번씩 호출되는 것을 확인 할 수 있습니다.


위 Scheduled 어노테이션으로 cron 주기를 설정한 문법에 대한 설명입니다.

먼저 저의 경우는 별표시(*) 6개를 스페이스를 구분으로 사용하였습니다만, 사실 기본은 7개의 별표시(*)에 스페이스 구분을 둡니다.

*  *  *  *  *  *  *
초 분 시 일 월 요일 년도(생략가능 - 생략시에는 매년의 의미)

cron은 위의 7자리 표현식으로 주기를 설정합니다.

먼저 * 표시는 ALL의 의미로 매초, 매분, 매시간, 매일, 매월, 매요일, 매년의 의미입니다.

일, 요일의 경우는 *대신 ?를 사용할 수도 있습니다. (뜻은 다른데, 결과는 같습니다.)

그리고 그외에 지정을 할 때는 숫자로 표시를 합니다. 참고로 요일의 경우는 1부터 7의 수를 사용하는데 1:일 2:월 3:화 4:수 5:목 6:금 7:토의 의미를 가집니다.

예로 「0 0 10 1 1 1」이라는 표현식으로 지정을 하게 되면 매년(생략됨) 1월 1일 10시 00분 00초의 월요일인 경우(화요일이면 실행하지 않습니다.) 실행하라는 문법이 됩니다. 이런 날이 있으려나 모르겠네요.

지정된 일자를 둘이상 지정을 할 때는 콤마로 구분을 합니다.

예로 「0,10 0 10 * * *」이라고 표현식으로 지정을 하게 되면 매년(생략됨) 매월 매일 10시 00분 0초와 10초에 실행하라라는 뜻이 됩니다.

초 설정에 0,10,20,30,40,50이라고 하면 0초, 10초, 20초, 30초, 40초, 50초에 실행하라는 뜻이 되는데 편하게 0/10라고 하면 10초 마다라는 의미가 되므로 좀 더 간단한 표현식을 나타낼 수 있습니다.

그리고 하이픈(-)으로 범위를 지정할 수도 있는데 일에 1-10이라고 하면 1일부터 10일까지라는 의미가 됩니다.


특수 표현식으로 L,W,#이 있는데 L은 마지막 날의 의미를 가지고 있습니다.일과 요일에서만 사용할 수 있는데 일에서 L를 사용하면 해당 달의 마지막 날, 요일에는 토요일을 의미합니다.

W는 일에서만 사용되는 데 가장 가까운 평일을 뜻합니다. 10W의 경우 10일이 토요일이면 9일에 실행. 10일이 일요일이면 11일에 실행하는 표현식입니다.

#은 요일에 사용되는 표현식입니다. 2#2라고 하면 두번째 주 월요일에 실행이라는 의미입니다.

정리하면 다음과 같습니다.

표현식 설명
* ALL의 의미로 매초, 매분, 매시간, 매일, 매월, 매요일, 매년
? 일 요일에서만 사용되는 조건 없음의 의미
/ 주기 반복의 의미
- 범위의 의미
L 일, 요일에서만 사용되는데 마지막날의 의미입니다.
W 일에서만 사용되는데 지정된 가장 가까운 평일을 찾습니다.
# 요일에서만 사용되는데 주#요일을 나타냅니다.

여기까지 JSP Spring 환경에서 scheduler의 cron을 사용하는 방법에 대한 설명이었습니다.


궁금한 점이나 잘못된 점이 있으면 댓글 부탁드립니다.