[Spring] Spring Batch + Quartz Scheduler (with. maven)

개요 

[앤젤 플러스] 회원 정보 갱신을 위한 배치 기능을 추가한 적이 있습니다. Quartz Scheduler를 사용하여 데이터 처리를 자동화했던 경험을 공유하고자 합니다. 

2022년 5월 12일일에 작성한 글입니다. (링크) 

 

Quartz Job Scheduler 

 

Quartz Job Scheduler는 오픈소스 스케줄러입니다. 
쿼츠는 자바 환경의 규모와 상관없이 사용이 가능하고 잡 실행에 유용한 스프링 부트 지원과 같이 오래전부터 스프링 연동을 지원합니다. 

 

의존성 추가 (maven dependency)

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

pom.xml에 dependency를 추가합니다. 만약 Library를 사용할 경우 jar를 다운받아 추가합니다.

 

Job 과 Task

Quartz는 일반 클래스로 동작하기 때문에 Spring DI를 사용할 수 없습니다.
따라서 @Autowired를 통해 Service를 호출하여도 null이 출력되며 동작하지 않습니다.

이를 해결하기 위해 Job 과 Task를 분리하여 코드를 작성해보겠습니다.

 

package com.study.common.batch.test;

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

public class TestBatchJob extends QuartzJobBean {
	
	private TestBatchTask testBatchTask;
	
	@Autowired
	public void setTestBatchTask(TestBatchTask testBatchTask) {
		this.testBatchTask = testBatchTask;
	}

	@Override
	protected void executeInternal(JobExecutionContext arg0) throws JobExecutionException {
		testBatchTask.task();
	}

}

Task를 주입하여 Spring DI 컨테이너가 사용할 수 있는 실제 작업이 일어나는 객체입니다.

스케줄러에 의해 Job 클래스가 호출되었을 때 해당 executeInternal 메소드를 실행합니다.

 

package com.study.common.batch.test;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;

import com.study.common.service.CommonService;

public class TestBatchTask {
	
	protected final Logger log = LoggerFactory.getLogger(this.getClass());
	
	@Autowired 
	CommonService commonService;
	
	// Scheduling
	public void task() {
		
		log.info("Spring Quartz Scheduler executed!");
        
		try {
			
			/* Task 작성 */

		} catch (Exception e) {
			logger.error("Error : {}", e.getMessage());
		}
	}

}

빈(Bean)으로 등록된 TestBatchTask 객체는 의존성 주입을 통해 Service 객체 사용이 가능합니다.
실제 스케줄링이 일어났을 때 task() 메소드가 실행됩니다.


Batch Context (batch-context.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.xsd">
	
	<!-- Task bean 생성 -->
	<bean id="testBatchTask" class="com.study.common.batch.TestBatchTask" />
	
  	<!-- Job -->
	<bean name="testBatchJob" class="org.springframework.scheduling.quartz.JobDetailFactoryBean">
		<property name="jobClass" value="com.study.common.batch.TestBatchJob" />
      	<!-- Task -->
		<property name="jobDataAsMap">
			<map>
				<entry key="testBatchTask" value-ref="testBatchTask" />
			</map>
		</property>
	</bean>
	 
  	<!-- quartz trigger 작성 -->
	<bean id="cronTrigger" class="org.springframework.scheduling.quartz.CronTriggerFactoryBean">
		<property name="jobDetail" ref="testBatchJob" />
		<!-- 1분마다 실행 -->
		<property name="cronExpression" value="0 0/1 * * * ?" />
	</bean>
	
  	<!-- quartz trigger 실행 -->
	<bean class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
		<property name="triggers">
			<list>
				<ref bean="cronTrigger"/>
			</list>
		</property>
	</bean>
	
	
</beans>
<!-- Task bean 생성 -->
<bean id="testBatchTask" class="com.study.common.batch.TestBatchTask" />

Spring IoC 컨테이너가 관리할 수 있도록 TestBatchTask 객체를 빈(Bean)으로 등록합니다.

 

<!-- Job -->
<bean name="testBatchJob" class="org.springframework.scheduling.quartz.JobDetailFactoryBean">
	<property name="jobClass" value="com.study.common.batch.TestBatchJob" />
  
    <!-- Task -->
	<property name="jobDataAsMap">
		<map>
			<entry key="testBatchTask" value-ref="testBatchTask" />
		</map>
	</property>
  
</bean>

JobDetailFactoryBean 클래스에 스케줄링하기 위한 Job 클래스를 주입합니다. 

jobDataAsMap에 Service를 작성하는 것이 아니라 실제로 작업할 Task 하나만 작성하여 사용합니다. (작업하는데 필요한 빈 객체(Bean)를 value-ref를 통해 참조)

 

<!-- quartz trigger 작성 -->
<bean id="cronTrigger" class="org.springframework.scheduling.quartz.CronTriggerFactoryBean">
	<property name="jobDetail" ref="testBatchJob" />
	<!-- 1분마다 실행 -->
	<property name="cronExpression" value="0 0/1 * * * ?" />
</bean>

<!-- quartz trigger 실행 -->
<bean class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
	<property name="triggers">
		<list>
			<ref bean="cronTrigger"/>
		</list>
	</property>
</bean>

스케줄러는 CronTrigger 방식으로 사용했으며, cronExpression을 설정하여 주기를 설정합니다. 이후 SchedulerFactoryBean을 통해 트리거를 등록해줍니다.

 

[Spring 레퍼런스] 26장 태스크(Task) 실행과 스케줄링
[스프링 배치] 쿼츠 Quartz 사용하여 배치 스케줄링
Quartz Job Scheduler란?