spring batch 를 쉽게 시작할 수 있게 해주는 starter 현재 시점에서 가장 최신에 나온 3.3.5 를 사용해주겠습니다. 3.3.5 에서는 spring batch 5.xx 버전을 사용합니다. spring batch 가 5로 나오면서 굉장히 많은 것들이 달라졌는데, 그건 글을 통해서 차근차근 알아가보겠습니다. (5로 새롭게 하면서 고생한 건 안비밀)
org.springframework.boot:spring-boot-starter-web
web 개발을 쉽게 시작할 수 있도록 도와주는 starter RESTful 웹 서서비스를 개발하기 위해서는 기본적으로 필요하기 때문에 거의 기본적으로 넣어주는게 좋습니다. API 호출을 통해 배치를 실행하도록 할거라 여기서도 사용해주도록 하겠습니다.
com.h2database:h2
Java 기반의 관계형 데이터베이스 In Memory DB 로 굉장히 가볍고 쉽게 사용할 수 있습니다. spring batch 를 사용할 때에는 DB 가 필요한데, 설치해야 하는 다른 DB 대신 h2 를 사용해주겠습니다.
(선택)org.projectlombok:lombok
반복되는 코드를 줄이기 위해 사용되는 라이브러리 Getter/Setter 등 개발 생산성을 높이기 위한 다양한 어노테이션을 제공하는 라이브러리 입니다. 해당 라이브러리는 사용하셔도 되고, 안사용하셔도 됩니다.
해당 build.gradle 을 실행해주고 나면 외부 라이브러리에 spring batch 관련 라이브러리들이 생긴 걸 확인할 수 있습니다.
그렇다면 Spring Batch 를 사용할 준비가 모두 완료되었습니다.
# 1-2. 간단한 Job 예제 만들어보기
그러면 본격적으로 Spirng Batch 를 사용해보겠습니다.
예제를 시작하기 전에 앞서서 Spring Batch 5 가 되면서 바뀐 점을 짚고 넘어가겠습니다.
Spring Batch 5 의 달라진 점 1 : @EnableBatchProcessing 기존에는 Spring Batch 의 기능을 사용하기 위해서 @EnableBatchProcessing 어노테이션을 무조건 사용해줘야 했습니다. 하지만, 버전 5 이상부터는 Spring Boot 3 과의 통합이 강화되었기 때문에 Spring Boot 를 사용하는 경우 자동으로 Batch 환경이 구성됩니다. @EnableBatchProcessing 를 사용해돈 되지만, 기본 구성과 충돌할 수 있습니다.
원래는 @EnableBatchProcessing 어노테이션을 반드시 !!!! 사용해야 Spring Batch 를 사용할 수 있었습니다.
하지만, Spring Batch 5 버전 부터는 사용하지 않아도 됩니다.
이것때문에 고생을 좀 많이 했는데, 해당 어노테이션의 여부에 따라서 Spring Batch 가 실행되는 방식 자체가 엄청나게 달라지더라고요.
그렇기 때문에 해당 예제에서는 사용하지 않도록 하겠습니다.
그러면 먼저 Config 파일을 만들어보도록 하겠습니다.
파일 이름은 SimpleJobConfig 로 만들어줍니다.
@Slf4j // 로그를 사용하기 위한 Lombok 어노테이션
@Configuration // Bean 을 정의 및 설정을 하기 위한 어노테이션
public class SimpleJobConfig {
}
그리고 위에 필요한 어노테이션들을 붙여주도도록 하겠습니다.
그런 다음 SimpleJobConfig 에서 배치를 동작하기 위한 Job 과 Step 코드를 작성해보겠습니다.
기존에 Spring Batch 를 사용하셨던 분들은 StepBuilderFactory, JobBuilderFactory 를 사용해서 코드를 작성하셨던 분들이 많았을 텐데요. Spring Batch 5 가 되면서 이 부분도 내용이 바뀌었습니다.
Spring Batch 5 의 달라진 점 2 : StepBuilderFactory, JobBuilderFactory Deprecated 기존에는 StepBuilderFactory와 JobBuilderFactor를 사용해 Job과 Step 을 구성하는 방식으로 batch 를 구성했습니다. 하지만, Spring Batch 5 에서는 Deprecated 되었기 때문에 각각 직접 명시하는 방식을 사용해야 합니다. https://github.com/spring-projects/spring-batch/wiki/Spring-Batch-5.0-Migration-Guide
Spring Batch 공식 문서에서도 위와 같이 사용하라고 안내하고 있습니다
그렇기 때문에 StepBuilderFactory 와 JobBuilderFactory 대신 각자 직접 명시해서 Step 과 Job 을 구성해보도록 하겠습니다.
@Bean
public Job simpleJob(JobRepository jobRepository, Step step) {
return new JobBuilder("simpleJob", jobRepository)
.start(step)
.build();
}
@Bean
public Step step(JobRepository jobRepository, PlatformTransactionManager platformTransactionManager) {
return new StepBuilder("simpleStep", jobRepository)
.tasklet((contribution, chunkContext) -> {
log.info(" #### simpleJob 실행 ####");
return RepeatStatus.FINISHED;
}, platformTransactionManager)
.build();
}
그러면 코드를 차근차근 한줄씩 살펴보겠습니다.
1. simpleJob Bean
public Job simpleJob(JobRepository jobRepository, Step step)
- JobBuilderFactory 대신 JobRepository 를 사용했습니다. - JobRepository 는 데이터를 저장하는데 사용하는 데이터 저장소를 의미합니다. - 사용한 이유는 Spring Batch 5 의 달라진 점 2를 확인해주세요
return new JobBuilder("simpleJob", jobRepository)
- JobBuilder 는 Job 객체를 사용하는데 사용됩니다. - 여기서 Job 의 이름은 SimpleJob 으로 지정했습니다.
.start(step)
- Job 은 배치 처리의 최상위 개념으로 여러 개의 Step 을 가질 수 있지만, 여기서는 한 개의 Step 만 사용했습니다.
- tasklet 은 단일 작업을 정의합니다. - tasklet 안의 람다 함수는 배치 작업이 실행될 때 출력됩니다. 여기선 로그에#### simpleJob 실행 #### 만 출력합니다. -RepeatStatus.FINISHED 를 반환함으로서 작업이 완료된 상태를 나타냅니다.
최종적으로 simpleJob 아래와 같이 실행됩니다.
1. simpleJob 이 실행되면, step 이 첫번째 Step 으로 시작됩니다.
2. step 내에서는 Tasklet 이 실행되며, 로그를 출력한 후 RepeatStatus.FINISHED 를 반환합니다.
3. 반환된 상태가 FINISHED 이기 때문에 step 은 성공적으로 완료되고, simpleJob 이 종료됩니다.
# 1-3. 실행하기
그러면 해당 Job 을 실행시켜봐야겠죠 ?
아직 별다른 설정을 하지 않았기 때문에 Application 을 실행시키면 해당 Job 도 자동으로 실행됩니다.
Application 이 실행되면서 아래와 같은 로그가 찍힙니다.
첫번째 줄 : simpleJob 이 실행되었으며, 파라미터로는 아무것도 없음을 알 수 있습니다.
두번째줄 : simpleStep 이 실행되었습니다.
세번째 줄 : simpleStep 의 log 가 정상적으로 출력됩니다.
네번째 줄 : simpleStep 이 실행되는데 걸리는 시간은 6ms 였습니다.
다섯번째 줄 : simpleJob 이 오류없이 정상적으로 완료되었음을 보여줍니다.
Spring Batch 를 통해 간단한 예시를 만들어보았습니다.
하지만, 보이는 불편한 점들이 있습니다.
첫번째로, Spring Applciation 이 실행될 때 Batch 가 실행되는게 아니라 실행 시점을 제어할 수 있으면 좋겠습니다.
두번째로, 각 Job 들의 상태를 DB 를 통해서 관리해보고 싶네요.
이 점들을 반영해서 H2 DB 를 사용해서 API 로 호출할 수 있는 배치를 만들어보도록 하겠습니다.
# 2-1. H2 를 사용하기 위해 application.yaml 세팅하기
Spring Batch 를 사용하면 DB 를 무조건 같이 사용해줘야 합니다.
그 이유는 Batch 내에서 돌아가는 Step 들을 저장하는 테이블들을 Spring Batch 가 관리하기 때문입니다.
만들어지는 sql 들은 spring-batch-core 아래에서 확인할 수 있습니다.
외부 라이브러리 > Gradle: org.springframework.batch:spring-batch-core:5.1.2 하위의
org > springframework > batch > core 하위에 해당 sql 들을 확인할 수 있습니다
사용되는 DB 들에 따라서 정말 다양한 sql 이 준비되어 있는 것을 알 수 있습니다.
schema-*.sql 은 테이블을 create 하는 sql
schema-drop-*.sql 은 테이블을 drop 하는 sql 들입니다.
저희는 h2 DB 를 사용할 거니깐 schema-h2.sql 을 확인해보겠습니다.
CREATE TABLE BATCH_JOB_INSTANCE (
JOB_INSTANCE_ID BIGINT GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY ,
VERSION BIGINT ,
JOB_NAME VARCHAR(100) NOT NULL,
...
이 테이블 외에도 정말 많은 테이블들이 Batch 를 관리하기 위해서 사용됩니다.
그러면 일단, H2 를 사용하기 위해서 application.yaml 을 세팅해보겠습니다.
job 들이 application 이 실행될 때 임의로 실행되지 않도록 batch.job.enable 을 false 로 설정해줍니다.
application.yaml 을 추가한 후 다시 Application 을 실행시켜보면
Application 실행 로그에서 Job 은 실행되지 않은 걸 확인할 수 있습니다.
그리고 /h2-console URL 을 통해 h2 console 을 접속해보겠습니다.
h2 console 이 정상적으로 작동하는 걸 확인할 수 있고, Driver Class 와 JDBC URL 그리고 User Name 을 application.yaml 에서 입력했던 내용과 동일하게 넣어줍니다.
Connect 를 누르면 콘솔에 정상적으로 접속이 됩니다.
접속하고 나면 BATCH 관련 테이블들이 많이 생긴 것을 확인할 수 있습니다.
각각 어떤 역할을 하는지 간단하게 알아보겠습니다.
테이블명
설명
BATCH_JOB_EXECUTION
Job 실행 정보(상태, 시작/종료 시간 등)를 저장
BATCH_JOB_EXECUTION_CONTEXT
Job 실행 중 공유되는 컨텍스트 데이터를 저장
BATCH_JOB_EXECUTION_PARAMS
Job 실행 시 사용된 파라미터를 저장
BATCH_JOB_INSTANCE
Job의 고유 인스턴스 정보를 저장(실행 간 재사용 가능)
BATCH_STEP_EXECUTION
Step 실행 정보(상태, 시작/종료 시간 등)를 저장
BATCH_STEP_EXECUTION_CONTEXT
Step 실행 중 공유되는 컨텍스트 데이터를 저장
의 역할을 하고 있습니다.
그러면 본격적으로 배치를 실행하는 API 를 만들어보겠습니다.
# 2-2. 배치 호출 API 만들기
Job 이 SimpleJob 이니깐 API 도 GET /simple 로 만들어보도록 하겠습니다.
Controller 역할을 할 자바 파일을 ApiController.java 로 만들어주겠습니다.
@RestController
@RequiredArgsConstructor
public class ApiController {
private final JobLauncher jobLauncher;
private final JobRegistry jobRegistry;
@GetMapping("/simple")
public String simpleApi() throws Exception {
jobLauncher.run(jobRegistry.getJob("simpleJob"), new JobParameters());
return "ok";
}
}
Job 을 실행하기 위해서 JobLauncher 와 JobRegistry 총 두개의 핵심적인 클래스가 필요합니다.
JobLauncher 는 Spring Batch 에서 Job 을 실행하고, JobRegistry 는 Job 객체를 이름으로 관리해줍니다.
GET /simple API 가 호출되게 되면 jobRegistry 에서 simpleJob 을 찾고, jobLauncher 가 실행시켜주는 아주 간단한 예제입니다.
그리고 simpleJob 은 파라미터가 필요없기 때문에 비어있는 new JobParameters 를 만들어서 리턴합니다.
그러면 /simple API 를 호출시켜보도록 하겠습니다.
/simple API 를 호출하면 ok 값이 출력되고
simpleStep 이 실행된 것을 확인할 수 있습니다.
그리고 h2-console 에 들어가서 확인하면 BATCH_JOB_EXECUTION 을 확인해보겠습니다.
정상적으로 실행된 것을 확인할 수 있습니다 !!
한번더 실행하게 되면
해당 Step 이 이미 완료되었다는 로그와 함께 다시 실행되지 않습니다.
그러면 BATCH_JOB_EXECUTION 에서도 확인해볼까요?
EXIT_MESSAGE 가 로그에서 보인것과 동일하게 남으면서 이미 완료되었다는 것을 확인 할 수 있습니다.
# 결론
간단한 Spring Batch 예제를 통해서 Spring Batch 에 대해서 알아보았습니다.
예제를 준비하면서 Spring Batch 5 때문에 좀 고생을 많이 했는데요 ,,,,
아직 Spring Batch 에 발만 담궜으니 다음 포스팅은 Spring Batch 에 대해 조금 더 복잡한 정보로 찾아오겠습니다.