Spring batch 예제 - spring batch yeje

[스프링/Spring] 스프링 배치(Spring Batch) 적용하는 방법을 정리한다.


1. 개발환경

- Eclipse 2021-06 (4.20.0)

- JDK 1.8

- Apache Tomcat v8.5


1. Maven 추가하기

1) org.springframework.batch.spring-batch-core

<!-- https://mvnrepository.com/artifact/org.springframework.batch/spring-batch-core -->
<dependency>
	<groupId>org.springframework.batch</groupId>
	<artifactId>spring-batch-core</artifactId>
<!--<version>3.0.10.RELEASE</version>-->
    <version>4.3.3</version>
</dependency>

2) org.springframework.spring-test

<!-- https://mvnrepository.com/artifact/org.springframework/spring-test -->
<dependency>
	<groupId>org.springframework</groupId>
	<artifactId>spring-test</artifactId>
	<version>4.3.25.RELEASE</version>
</dependency>

3) org.springframework.batch.spring-batch-test

<!-- https://mvnrepository.com/artifact/org.springframework.batch/spring-batch-test -->
<dependency>
	<groupId>org.springframework.batch</groupId>
	<artifactId>spring-batch-test</artifactId>
	<version>4.3.3</version>
<!--<scope>test</scope>-->
</dependency>

2. Job 예제 만들기(Job 작성하기)

1) job id는 demojob으로, job에는 1개 이상의 Step 있을 수 있다.

- Job에 관한 설명은 아래의 링크에서 볼 수 있다.

- 각 스텝의 id는 demoStep01과 demoStep02로 설정한다.

- demoStep01이 끝나면, 다음 스텝은 demoStep02가 실행된다.

<job id="demoJob" xmlns="http://www.springframework.org/schema/batch">
	<description> Spring batch demo </description>
	<step id="demoStep01" next="demoStep02">
		<tasklet ref="demo01Tasklet" />
	</step>
	<step id="demoStep02">
		<tasklet ref="demo02Tasklet" />
	</step>
</job>

https://yongku.tistory.com/category/IT/%EC%8A%A4%ED%94%84%EB%A7%81%28Spring%29

'IT/스프링(Spring)' 카테고리의 글 목록

츄르 사려고 코딩하는 집사

yongku.tistory.com

Spring batch 예제 - spring batch yeje

2) Step에 설정한 Tasklet을 Bean 주입한다.

- 스프링 배치(Spring Batch)는 Tasklet 방식과 Chunk 방식이 있는데, Tasklet 방식은 단일 Task를 수행한다.

- 즉, 각 Step에서는 1개의 정의된 작업만 수행한다.

<bean id="demo01Tasklet" class="com.batch.tasklet.Demo01Tasklet" scope="step" />
	<!-- scope {step: 각 스텝마다 스텝에 종속된 고유한 빈을 만든다, 
		   prototype: 빈을 reference (참조) 할 때마다 새로운 빈을 반환한다, 
		   singleton: 배치 job이 생성될 때 하나의 고유한 빈을 만든다 }  -->

<bean id="demo02Tasklet" class="com.batch.tasklet.Demo02Tasklet" scope="step" />

3) 스프링 배치(Spring Batch)의 metadata를 담당하는 jobRepository를 Bean 주입한다.

- Job을 실행시키는 Job launcher와 Job, Step에서 jobRepository에 조회 및 저장을 한다.

- 각 JobExecution과 StepExecution을 생성.

<!-- 스프링 배치의 metadata를 담당하는 빈. -->
<bean id="jobRepository" 
	class="org.springframework.batch.core.repository.support.MapJobRepositoryFactoryBean">
</bean>

4) 스프링 배치(Spring Batch) Job을 실행하는 jobLauncher를 Bean 주입한다.

<!-- 스프링 배치 job을 실행하는 빈. -->
<bean id="jobLauncher"
	class="org.springframework.batch.core.launch.support.SimpleJobLauncher">
	<property name="jobRepository" ref="jobRepository" />
</bean>

5) 스프링 배치(Spring Batch)의 transactionManger와 스프링 배치(Spring Batch) job Test를 위해 쓰는 유틸리티인 jobLauncherTestUtils를 각각 Bean 주입한다.

<bean id="transactionManager"
	class="org.springframework.batch.support.transaction.ResourcelessTransactionManager" />
	
<!-- 스프링 배치 job을 테스트할 때 쓰는 유틸리티. -->
<bean id="jobLauncherTestUtils"
	class="org.springframework.batch.test.JobLauncherTestUtils" />

6) 위의 링크에 들어가면, Step에서는 Step 1개에 1개의 itemReader와 1개의 itemWriter, 1개의 itemProcessor를 가진다.

- 즉, 1:1 구조로 가지게 된다.

- 그래서, chunk를 (itemReader + itemProcessor + itemWriter)로 두는 경우, commit-interval에 의해 5번 반복하게 된다.

<step>
    <tasklet>
        <chunk reader="itemReader" processor="itemProcessor" 
        	writer="itemWriter" commit-interval="5" />
    </tasklet>
</step>

7) 전체 코드(demoJob.xml)

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:batch="http://www.springframework.org/schema/batch"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xmlns:context="http://www.springframework.org/schema/context"
	xmlns:tx="http://www.springframework.org/schema/tx"
	xmlns:jdbc="http://www.springframework.org/schema/jdbc"
	xsi:schemaLocation="http://www.springframework.org/schema/batch http://www.springframework.org/schema/batch/spring-batch.xsd 
		http://www.springframework.org/schema/jdbc http://www.springframework.org/schema/jdbc/spring-jdbc-4.3.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/tx http://www.springframework.org/schema/tx/spring-tx-4.3.xsd">
	
	<job id="demoJob"
		xmlns="http://www.springframework.org/schema/batch">
		<description> Spring batch demo </description>
		<step id="demoStep01" next="demoStep02">
			<tasklet ref="demo01Tasklet" />
		</step>
		<step id="demoStep02">
			<tasklet ref="demo02Tasklet" />
		</step>
	</job>

	<bean id="demo01Tasklet"
		class="com.batch.tasklet.Demo01Tasklet" scope="step" />
		<!-- scope {step: 각 스텝마다 스텝에 종속된 고유한 빈을 만든다, 
					prototype: 빈을 reference (참조) 할 때마다 새로운 빈을 반환한다, 
					singleton: 배치 job이 생성될 때 하나의 고유한 빈을 만든다 }  -->
	<bean id="demo02Tasklet"
		class="com.batch.tasklet.Demo02Tasklet" scope="step" />
		
	<!-- 스프링 배치의 metadata를 담당하는 빈. -->
	<bean id="jobRepository"
		class="org.springframework.batch.core.repository.support.MapJobRepositoryFactoryBean">
	</bean>
	
	<!-- 스프링 배치 job을 실행하는 빈. -->
	<bean id="jobLauncher"
		class="org.springframework.batch.core.launch.support.SimpleJobLauncher">
		<property name="jobRepository" ref="jobRepository" />
	</bean>

	<bean id="transactionManager"
		class="org.springframework.batch.support.transaction.ResourcelessTransactionManager" />
	
	<!-- 스프링 배치 job을 테스트할 때 쓰는 유틸리티. -->
	<bean id="jobLauncherTestUtils"
		class="org.springframework.batch.test.JobLauncherTestUtils" />
</beans>

3. Job 예제 만들기(*.java)

1) Demo01Tasklet.java

- Tasklet을 implements한다.

package com.yg.tasklet;

import org.apache.log4j.Logger;
import org.springframework.batch.core.StepContribution;
import org.springframework.batch.core.scope.context.ChunkContext;
import org.springframework.batch.core.step.tasklet.Tasklet;
import org.springframework.batch.repeat.RepeatStatus;

public class Demo01Tasklet implements Tasklet {
	
	private static Logger log = Logger.getLogger(Demo01Tasklet.class);
	
	public RepeatStatus execute(final StepContribution contribution, final ChunkContext chunkContext) throws Exception {
		log.debug("Demo01Tasklet 시작");
		log.debug("Demo01Tasklet 종료");
		return RepeatStatus.FINISHED;
	}
}

2) Demo02Tasklet.java

package com.yg.tasklet;

import org.apache.log4j.Logger;
import org.springframework.batch.core.StepContribution;
import org.springframework.batch.core.scope.context.ChunkContext;
import org.springframework.batch.core.step.tasklet.Tasklet;
import org.springframework.batch.repeat.RepeatStatus;

public class Demo02Tasklet implements Tasklet {
	
	private static Logger log = Logger.getLogger(Demo02Tasklet.class);
	
	public RepeatStatus execute(final StepContribution contribution, final ChunkContext chunkContext) throws Exception {
		log.debug("Demo02Tasklet 시작");
		log.debug("Demo02Tasklet 종료");
		return RepeatStatus.FINISHED;
	}
}

3) 스프링 배치(Spring Batch) Job Test Java

- Assert.assertEquals(X, Y)는 X와 Y가 같다면 통과.

package com.yg.test;

import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.batch.core.ExitStatus;
import org.springframework.batch.core.JobExecution;
import org.springframework.batch.test.JobLauncherTestUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

@RunWith(SpringJUnit4ClassRunner.class)
//Job예제를 만든 xml 경로 입력
@ContextConfiguration(locations = { "/com/yg/config/demojob.xml" })
public class DemoTestJob {

	@Autowired
	private JobLauncherTestUtils jobLauncherTestUtils;

	@Test
	public void testJob() throws Exception {
    	// job이 정상적으로 끝났는지 확인다.
		final JobExecution jobExecution = jobLauncherTestUtils.launchJob();
        
		Assert.assertEquals(ExitStatus.COMPLETED.getExitCode(), jobExecution.getExitStatus().getExitCode());
	}

}

참고자료

https://www.fwantastic.com/2019/12/spring-batch-2-metadata-jobrepository.html

[Spring Batch] 스프링 배치 강좌 2. Metadata와 JobRepository 알아보기

www.fwantastic.com

Spring batch 예제 - spring batch yeje