2021. 4. 14. 14:25ㆍspring
시작하기에 앞서 스프링 배치 Intro를 읽지 않았다면 먼저 보고 오자.
이전 글: [Spring Batch] Intro - 스프링 배치 기본 개념 익히기
새로운 것을 배울때 Hello World를 빼먹을수 없다. 초 심플한 배치 job을 만들어보자.
프로젝트 만들기
STS (Spring Tools Suite) 기준으로 작성되었다.
STS 다운로드: https://spring.io/tools
File -> New -> Maven Project -> Create a simple project (skip archetype selection) 클릭.
다음과 같이 입력.
Group Id: com.fwantastic
Artifact Id: spring-batch-example
Version: 0.0.1-SNAPSHOT
Packaging: jar
Name: Spring Batch example
Description: Spring Batch example
앞으로 매번 새로운 프로젝트를 만들지 않고 하나에 프로젝트에 예제들을 계속 추가하자.
pom.xml
pom.xml은 디펜던시를 관리하는 설정 파일이다. 스프링 개발자라면메이븐을 알아야한다. 만약 모른다면 구글링 해보자.
프로젝트 root level에pom.xml파일을 생성하자.src폴더와 같은 레벨에 있어야 한다.
이번 예제에선 필요 없는 디펜던시들도 일부러 넣었다. 한 프로젝트에 여러 예제를 넣을 거라서 미리 넣었으니 그냥 이런 것들을 쓰게 될 거구나 라고만 알고 있자. 디펜던시마다 주석을 달았으니 한 번씩 읽어보자.
pom.xml
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.fwantastic</groupId>
<artifactId>spring-batch-example</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>Spring Batch example</name>
<description>Spring Batch example</description>
<!-- 버전 관리 섹션 -->
<properties>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
<spring.batch.version>4.2.1.RELEASE</spring.batch.version>
<spring.version>5.2.2.RELEASE</spring.version>
<hibernate.version>5.4.10.Final</hibernate.version>
<apache.dbcp2.version>2.7.0</apache.dbcp2.version>
<h2.version>1.4.200</h2.version>
<junit.version>4.12</junit.version>
</properties>
<dependencies>
<!-- 스프링 배치의 코어를 담당하는 파트들을 가지고 있다. -->
<dependency>
<groupId>org.springframework.batch</groupId>
<artifactId>spring-batch-core</artifactId>
<version>${spring.batch.version}</version>
</dependency>
<!-- DB table과 Java간의 매핑을 가능케 해준다. -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-orm</artifactId>
<version>${spring.version}</version>
</dependency>
<!-- spring-orm은 인터페이스이고 hibernate은 구현체. -->
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-core</artifactId>
<version>${hibernate.version}</version>
</dependency>
<!-- 디비 관련 유틸리티. -->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-dbcp2</artifactId>
<version>${apache.dbcp2.version}</version>
</dependency>
<!-- getter/setter를 자동으로 만들어준다. -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.10</version>
<scope>provided</scope>
</dependency>
<!-- ########## 테스트 관련 디펜던시들 ########## -->
<!-- <scope>test</scope>은 테스트 코드에서만 사용 가능하다. -->
<!-- 스프링 배치 어플리케이션 테스트 유틸리티. -->
<dependency>
<groupId>org.springframework.batch</groupId>
<artifactId>spring-batch-test</artifactId>
<version>${spring.batch.version}</version>
<scope>test</scope>
</dependency>
<!-- 단위 테스트 -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>${junit.version}</version>
<scope>test</scope>
</dependency>
<!-- 메모리상에서 돌아가는 디비. 단위 테스트에 많이 쓰임. -->
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<version>${h2.version}</version>
<scope>test</scope>
</dependency>
</dependencies>
</project>
tasklet
Intro에서step을 간단히 보았다. 설명하지 않은tasklet이란게 나오는데,step정의하는 법을 보자.
<step>
<tasklet>
<chunk reader="itemReader" processor="itemProcessor"
writer="itemWriter" commit-interval="5" />
</tasklet>
</step>
이처럼chunk(reader + processor + writer) 를 사용하면읽기 -> 가공하기 -> 쓰기의 반복인데 chunk 없이한 번만 실행하도록 하는 것도 가능하다.
src/main/java에com.fwantastic.example1패키지를 만들고 아래 클래스를 추가하자.
HelloWorldTasklet.java
package com.fwantastic.example1;
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;
/**
* 두 개의 메세지만 출력하고 끝나는 단순한 tasklet.
*/
public class HelloWorldTasklet implements Tasklet {
public RepeatStatus execute(final StepContribution contribution, final ChunkContext chunkContext) throws Exception {
System.out.println("작업 시작...");
// 원하는 작업을 여기에서 할 수 있다.
System.out.println("작업 완료!");
return null;
}
}
execute메소드가null을 반환하면RepeatStatus.FINISHED를 반환하는 것과 같은 의미를 가진다. 한마디로 반복 없이 한 번만 실행된다는 소리다.
HelloWorldTasklet은tasklet인터페이스의구현체다.step이 실행되면 배치 프레임워크가 알아서execute메소드를 찾아 실행한다. 그럼 작업 시작...과 작업 완료! 메세지를 출력하고 끝난다.
job
다음으로 job을 작성해보자. src/main/resources 폴더에 com/fwantastic/example1 폴더를 만들고 아래의 xml 파일을 추가하자.
hello_world_job.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="helloWorldJob"
xmlns="http://www.springframework.org/schema/batch">
<description>
첫 스프링 배치 어플리케이션.
콘솔에 로그를 찍고 끝나는 간단한 스텝 예제.
</description>
<step id="helloWorldStep">
<tasklet ref="helloWorldTasklet" />
</step>
</job>
<!-- Tasklet -->
<!-- scope은 빈을 어떻게 생성할지 결정한다. 세개의 scope 종류를 보자.
- step: 각 스텝마다 스텝에 종속된 고유한 빈을 만든다.
- prototype: 빈을 reference (참조) 할 때마다 새로운 빈을 반환한다.
- singleton: 배치 job이 생성될 때 하나의 고유한 빈을 만든다.
-->
<bean id="helloWorldTasklet"
class="com.fwantastic.example1.HelloWorldTasklet" scope="step" />
<!-- Misc Beans -->
<!-- 해당 섹션에 있는 빈들은 별도의 xml로 관리하는 것이 좋다.
재사용을 위해 나중에 common.xml을 만들어보자. -->
<!-- 스프링 배치의 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>
테스트
배치job을 다 만들었으니 테스트 해보자.src/test/java에com.fwantastic.example1패키지를 만들고 아래 junit 클래스를 추가하자.
TestHelloWorldJob.java
package com.fwantastic.example1;
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 위치 지정
@ContextConfiguration(locations = { "/com/fwantastic/example1/hello_world_job.xml" })
public class HelloWorldJobTest {
@Autowired
private JobLauncherTestUtils jobLauncherTestUtils;
@Test
public void testJob() throws Exception {
final JobExecution jobExecution = jobLauncherTestUtils.launchJob();
// job이 정상적으로 끝났는지 확인다.
Assert.assertEquals(ExitStatus.COMPLETED.getExitCode(), jobExecution.getExitStatus().getExitCode());
}
}
실행하면 콘솔에 여러 메세지들이 찍혀있을 것이다.
INFO: Job: [FlowJob: [name=helloWorldJob]] launched with the following parameters: [{random=278562}]
Dec 11, 2019 9:30:46 PM org.springframework.batch.core.job.SimpleStepHandler handleStep
INFO: Executing step: [helloWorldStep]
작업 시작...
작업 완료!
INFO: Job: [FlowJob: [name=helloWorldJob]] completed with the following parameters: [{random=278562}] and the following status: [COMPLETED]
이로서 길다면 길고 짧다면 짧은 Hello World 예제가 끝이 났다. 처음엔 어려워 보일 수도 있으니 복붙 하지 말고 직접 만들어보는 연습을 충분히 하자.
'spring' 카테고리의 다른 글
[퍼옴] [Spring Batch] 스프링 배치 강좌 3. JobExecutionContext를 활용하여 스텝간 데이터 공유하기 (0) | 2021.04.14 |
---|---|
[퍼옴] [Spring Batch] 스프링 배치 강좌 2. Metadata와 JobRepository 알아보기 (0) | 2021.04.14 |
[퍼옴] [Spring Batch] Intro - 스프링 배치 기본 개념 익히기 (0) | 2021.04.14 |
Spring Boot 개념 (0) | 2021.04.14 |
[퍼옴] Spring Batch 주요 개념 (0) | 2021.04.14 |