Spring Batch 를 학습하기 위한 시리즈 글로 Spring Batch 5.1.0 버전을 기반으로 작성합니다.
프로젝트 환경
Spring Batch 를 실습하기 위해 먼저 프로젝트부터 생성하겠습니다. 다음과 같은 버전으로 프로젝트를 구성했습니다.
- Gradle(8.2.1)
- Spring Boot(3.2.1)
- Java(17)
- MySql(8.0.23)
또한 실습에 필요한 의존성은 다음과 같습니다.
- Spring-Data-JPA(3.2.1)
- Spring-Batch(5.1.0)
- Lombok(1.18.30)
- MySql-Connector(8.1.0)
프로젝트 생성 시 Spring Initializr 를 통해 필요한 의존성을 선택하여 생성하면 build.gralde
파일은 다음과 같습니다.
plugins {
id 'java'
id 'org.springframework.boot' version '3.2.1'
id 'io.spring.dependency-management' version '1.1.4'
}
group = 'io.ones1kk'
version = '0.0.1-SNAPSHOT'
java {
sourceCompatibility = '17'
}
configurations {
compileOnly {
extendsFrom annotationProcessor
}
}
repositories {
mavenCentral()
}
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-batch'
implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
compileOnly 'org.projectlombok:lombok'
runtimeOnly 'com.mysql:mysql-connector-j'
annotationProcessor 'org.projectlombok:lombok'
testImplementation 'org.springframework.boot:spring-boot-starter-test'
testImplementation 'org.springframework.batch:spring-batch-test'
}
tasks.named('test') {
useJUnitPlatform()
}
데이터베이스 설정
데이터 베이스는 In-memory DB 로 유명한 H2 로 설정하는 방법도 있으나 저는 이미 로컬에 Docker 로 구성된 MySql 환경이 있어 이를 그대로 사용하겠습니다. 또한 해당 글은 Sprig Batch 에 대한 글이니 설정하는 방식에 대한 자세한 설명은 생략하고 구성된 파일과 명령어로 대체하겠습니다.
1. Docker 및 Docker Compose 설치
brew update
brew install cask docker
brew install cask docker-compose
docker -v
Docker version 20.10.23, build 7155243
docker-compose -v
Docker Compose version v2.15.1
2. docker-compose.yml 작성
version: '3'
services:
local_db_root:
platform: linux/x86_64
image: library/mysql:8.0.23
container_name: mysql-8.0.23
restart: always
command:
- --character-set-server=utf8mb4
- --collation-server=utf8mb4_unicode_ci
ports:
- "3306:3306"
environment:
MYSQL_ROOT_PASSWORD: root
TZ: Asia/Seoul
volumes:
- ./db/mysql/data:/var/lib/mysql
MySql 버전과 ports, volumes, platform... 과 같은 속성들은 개인의 환경에 맞춰 알맞게 설정하기 바랍니다.
3. DB 접속 및 생성
CLI 또는 Database IDE 를 사용하여 정상적으로 데이터베이스가 생성되었는지 확인합니다.
저는 IDE를 사용하여 아래와 같이 정상적으로 생성되었음을 확인했습니다.
그 후 root 계정으로 접속하여 새로운 데이터베이스와 유저를 생성합니다.
# 데이터 베이스 'batch_db' 생성
CREATE DATABASE batch_db CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci ;
# 유저 생성
CREATE USER 'admin'@'%' IDENTIFIED BY 'admin' PASSWORD EXPIRE NEVER;
# 권한 부여
GRANT ALL PRIVILEGES ON batch_db.* TO 'admin'@'%';
# flush
FLUSH PRIVILEGES;
4. 애플리케이션 설정
위에서 생성된 데이터베이스 정보를 기반으로 application.yml
을 다음과 작성할 수 있습니다.
spring:
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:13306/batch_db
username: admin
password: admin
type: com.mysql.cj.jdbc.MysqlDataSource
jpa:
hibernate:
ddl-auto: update
show-sql: true
properties:
hibernate.format_sql: true
dialect: org.hibernate.dialect.MySQL8Dialect
또한 기본적인 JPA 에 대한 설정도 작성했습니다. ddl-auto
는 변경된 부분만 반영되는 update
전략으로 설정했습니다. 실제 실행되는 query 를 식별하고 포맷된 로깅을 위해 show-sql
, hibernate.format_sql
를 true로 설정했습니다. 마지막으로 dialect
은 데이터베이스와 버전에 알맞은 MySQL8Dialect
을 설정했습니다.
메타 데이터 테이블
이제 프로젝트 환경 구성이 완료되었습니다.
// 5.0.0 버전부터는 @EnableBatchProcessing 어노테이션은 더 이상 필요하지 않습니다.
@SpringBootApplication
public class SpringBatchApplication {
public static void main(String[] args) {
SpringApplication.run(SpringBatchApplication.class, args);
}
}
하지만 애플리케이션을 실행하기 이전에 한가지 더 선행되어야 할 것이 있습니다. 그것은 바로 메타 데이터 테이블들을 생성해야 합니다. Spring Batch는 배치 작업을 위해 메타 데이터들을 통해서 배치 작업의 상태를 추적하고 관리합니다.
다음은 주요 메타 테이블에 대한 설명입니다.
- BATCH_JOB_INSTANCE: 배치 작업은 Job 이 실행될 때마다 새로운 인스턴스가 생성됩니다. 해당 Job 인스턴스를 저장하기 위한 테이블입니다.
- BATCH_JOB_EXECUTION: Job 인스턴스에 대한 실행 정보를 저장합니다. 작업이 성공적으로 완료되었는지 또는 실패했는지와 같은 정보가 포함됩니다.
- BATCH_STEP_EXECUTION: 각 배치 Step 의 실행 정보를 저장합니다. 하나 이상의 테스크를 수행한 Step 의 실행 정보가 저정됩니다.
- BATCH_JOB_EXECUTION_PARAMS: 배치 작업 실행에 전달된 매개변수를 저장합니다. 배치 작업이 실행될 때 전달된 매개변수가 여기에 저장됩니다.
- BATCH_JOB_SEQ: 배치 작업 인스턴스 및 실행 정보에 대한 고유 식별자를 생성하는 데 사용됩니다.
이런 메타 테이블을 H2 DB를 제외한 다른 벤더사의 DB는 개발자가 직접 생성해야합니다. 아래와 같이 사용하는 IDE 에서 파일 검색을 진행하면 각 데이터베이스와 용도에 알맞은 .sql
파일을 찾을 수 있습니다.
알맞은 .sql
파일을 찾아서 파일 내부에 있는 Query 문을 실행시키면 총 9개의 메타 테이블 생성됩니다.
Job 생성
Spring Batch 가 v5.1.0
으로 버전이 올라가면서 새롭게 추가된 내용들이 있습니다. 변경된 내용을 간략하게 소개하겠습니다.
다양한 JobParameter Type
4 버전까지는 4개의 Type(Long, Double, String, Date)만을 지원했지만 5 버전부터는 다양한 타입을 지원합니다.
public class JobParameter<T> implements Serializable {
private final T value;
private final Class<T> type;
...
}
JobParameter 클래스에 타입 파라미터를 통해 다양한 타입을 JobParameter 로 사용 가능해졌습니다. 따라서 기본적이 표기법이 아래와 같이 변경되었습니다.
- 기본 표기법:
parameterName=parameterValue,parameterType,identificationFlag
- 확장 표기법:
parameterName='{"value": "parameterValue", "type":"parameterType", "identifying": "booleanValue"}'
명시적 자동 설정
JobBuilderFactory, StepBuilderFactory 가 deprecated 됐습니다. 그 이유는 숨겨진 자동 설정과 관련된 내용입니다.
@Deprecated(since = "5.0.0", forRemoval = true)
public class JobBuilderFactory {
...
public JobBuilder get(String name) {
return new JobBuilder(name, this.jobRepository);
}
}
@Deprecated(since = "5.0.0", forRemoval = true)
public class StepBuilderFactory {
...
public StepBuilder get(String name) {
return new StepBuilder(name, this.jobRepository);
}
}
위 두 메소드는 각각의 Factory 클래스에서 Job 과 Step 을 생성하는 메소드입니다. 두 개의 Builder 를 생성하기 위해서는 JobRepository 를 필요로 하는데 이는 해당 메소드를 사용하는 개발자가 문서를 읽지 않는한 인지하기 어렵다는 이유에서 입니다. 즉 JobRepository 에 대한 의존성을 숨기고 있기 때문에 이를 명시적으로 선언하여 사용하는 것을 권고한 것입니다.
변경된 내용과 v4.x.x
-> v5.1.0
마이그레이션에 대한 자세한 내용은 해당 링크와 해당 링크를 참고하시면 됩니다.
이제 그디어 배치 애플리케이션 실행을 위한 코드를 작성할 수 있습니다.
@Slf4j
@Configuration
public class TestJobConfiguration {
@Bean
public Job myJob(JobRepository jobRepository, PlatformTransactionManager transactionManager) {
return new JobBuilder("myJob", jobRepository)
.start(step(jobRepository, transactionManager))
.build();
}
@Bean
public Step step(JobRepository jobRepository, PlatformTransactionManager transactionManager) {
return new StepBuilder("step1", jobRepository)
.tasklet(tasklet(), transactionManager)
.build();
}
public Tasklet tasklet() {
return (contribution, chunkContext) -> {
log.info(">>> execute tasklet");
return RepeatStatus.FINISHED;
};
}
}
위의 코드는 Job 을 실행시키기 위한 기본적인 코드입니다. 모든 Job 과 Step은 Bean 으로서 관리되기 때문에 @Configuration
을 선언한 설정 파일에서 Bean 으로 선언합니다. Job 이란 하나의 배치 작업 단위를 나타내는 용어로 단순한 Step 인스턴스의 컨테이너 개념으로 여러 개의 Step 으로 구성될 수 있습니다.
다음으로 myJob
을 구성하는 step
을 살펴 보도록 하겠습니다.
출처
Step 은 Job 의 각 실행 단위를 나타냅니다. 일반적으로 하나의 Step 은 특정한 처리를 담당하며 특정한 비즈니스 로직을 담당하여 구성되며 이런 Step 들을 조합하여 사용합니다. 이 중에서 Step 은 두가지 방식으로 구성이 될 수 있는데 하나의 Tasklet과 ItemReader & ItemProcessor & ItemWriter 한 묶음으로 구성될 수 있습니다.
여기서 Tasklet 이란 간단한 작업을 수행하는 데 사용되는 사용자 정의의 비즈니스 로직을 작성하는 한 덩어리의 Step 의 구성 요소로 이해하면 됩니다. 예제를 단순화하기 위해 Tasklet 을 사용하여 작성했습니다.
실행
이제 작성된 코드들을 기반으로 애플리케이션을 실행합니다.
COMPLETED 상태로 Job이 종료되었다고 로그가 찍힙니다.
select * from batch_job_instance;
Job Instance 도 잘 생성되었습니다.
select job_execution_id, job_instance_id, status, exit_code, start_time, end_time from batch_job_execution;
마지막으로 Job Execution 도 COMPLETED 상태로 종료된 것을 확인할 수 있습니다.
이것으로 간단하게 Spring Batch 애플리케이션 프로젝트 생성부터 환경 설정 그리고 예제 Job 까지 생성하여 실행까지 시켜보았습니다. 위와 같이 구성한 프로젝트를 기반으로 Spring Batch 의 다양한 기능을 실습하고 공부해보도록 하겠습니다.
작성한 코드는 Github 에서 확인할 수 있습니다.
오탈자 및 오류 내용을 댓글 또는 메일로 알려주시면, 검토 후 조치하겠습니다.
'Spring > Batch' 카테고리의 다른 글
[Spring] Spring Batch Job 등록부터 실행까지(1) (1) | 2024.01.22 |
---|---|
[Spring] Spring Batch란? (2) | 2023.12.18 |