최근 스프링 배치를 사용하려고 했는데 spring batch 5버전이였다. 어떤점이 바뀌었나 궁금해서 찾아서 정리해봤다.
Spring Batch 5에서는 Spring Framework의 버전이 Spring Framework 6으로 업그레이드되며, 이는 Java 17을 필요로 한다.
따라서, Spring Batch의 Java 버전 요구사항도 Java 17로 증가하게 되었다.
GraalVM을 사용해서 Spring Batch에서 기본적으로 컴파일하는데 필요한 AOT(Ahead-Of-Time) process 및 Runtime hint를 제공하여 성능이 향상되었다.
아래는 해당 코드로 테스트한 벤치마크 결과이다.
여기서 나온 값들은 다음의 환경에서 샘플을 10번 실행한 결과의 평균이다.
이 벤치마크의 결과는 Spring Batch의 시작 시간이 2배 빠르고 런타임에서는 거의 10배가 빠른 결과이다.
4.x 버전까지는 4개의 Type(Long, Double, String, Date)만을 지원했다. Srping Batch에서 jobParameter를 다루는 것을 간소화하기 위해 편리한방법이였지만, 사용자 측면에서는 제약이 될 수 있다.
예를 들어, boolean이나 사용자 정의 Type을 JobParamter로 사용하고 있다면 이를 위해 추가적인 변환 작업이 필요하기 때문이다.
아래는 JobParameter의 변경사항인데, Generic이 들어간 걸 확인할 수 있다.
---public class JobParameter implements Serializable {
+++public class JobParameter<T> implements Serializable {
--- private Object parameter;
+++ private T value;
--- private ParameterType parameterType;
+++ private Class<T> type;
}
v4에서는 JobParameter를 아래와 같이 표기했다.
[+|-]parameterName(parameterType)=parameterValue
여기서 parameterType은 [string,long,double,date] 하나였다.
v5에서는 아래와 같이 변경되었다.
parameterName=parameterValue,parameterType,identificationFlag
여기서 parameterType은 파라미터의 타입의 완전한 이름이다. 예를 들면 아래와 같다.
schedule.date=2022-12-12,java.time.LocalDate
2022-12-12 값을 가진 java.time.LocalDate 타입의 JobParameter로 변환된다. 여기서 identificationFlag
는 선택사항이며 기본값은 true이다.
이러한 표기법은 대부분 사용할때 문제가 없지만 값에 콤마가 포함된다면 문제가 발생할 수 있다. 이러한 경우 스프링부트의 Json 애플리케이션 속성에서 영감을 받아서 도입한 확장 표기법을 사용할 수 있다.
parameterName='{"value": "parameterValue", "type":"parameterType", "identifying": "booleanValue"}'
기본적으로는 DefaultJobParametersConverter적용되지만 위와 같은 결과는 JsonJobParametersConverter을 이용한 결과이다.
이 변경 사항으로 Spring Batch의 메타 테이블에도 변화가 발생했다.
CREATE TABLE BATCH_JOB_EXECUTION_PARAMS (
JOB_EXECUTION_ID BIGINT NOT NULL ,
--- TYPE_CD VARCHAR(6) NOT NULL ,
--- KEY_NAME VARCHAR(100) NOT NULL ,
--- STRING_VAL VARCHAR(250) ,
--- DATE_VAL DATETIME(6) DEFAULT NULL ,
--- LONG_VAL BIGINT ,
--- DOUBLE_VAL DOUBLE PRECISION ,
+++ PARAMETER_NAME VARCHAR(100) NOT NULL ,
+++ PARAMETER_TYPE VARCHAR(100) NOT NULL ,
+++ PARAMETER_VALUE VARCHAR(2500) ,
IDENTIFYING CHAR(1) NOT NULL ,
constraint JOB_EXEC_PARAMS_FK foreign key (JOB_EXECUTION_ID)
references BATCH_JOB_EXECUTION(JOB_EXECUTION_ID)
);
아마 Spring Batch 4를 사용해본 사람이라면 아래와 같은 구성으로 사용했을 것이다.
// Sample with v4
@Configuration
@EnableBatchProcessing
public class MyJobConfig {
@Autowired
private JobBuilderFactory jobBuilderFactory;
@Bean
public Job myJob(Step step) {
return this.jobBuilderFactory.get("myJob")
.start(step)
.build();
}
}
하지만 이러한 구성은 JobBuilder에 하나의 설정이 추가되는데 그게 바로 JobRepository이다. 이런 암시적인 구성때문에 JobRepository가 생성되고 설정되었다는 사실을 숨겨버린다.
그래서 아래와 같이 명시적인 방법으로 변경되었다.
// Sample with v5
@Configuration
@EnableBatchProcessing
public class MyJobConfig {
@Bean
public Job myJob(JobRepository jobRepository, Step step) {
return new JobBuilder("myJob", jobRepository)
.start(step)
.build();
}
}
더 자세하게 알고싶다면 해당 이슈를 참고해보면 좋다.
Step쪽을 살펴보면 transactionManager가 생겨난걸 볼 수 있다.
// Sample with v4
@Configuration
@EnableBatchProcessing
public class MyStepConfig {
@Autowired
private StepBuilderFactory stepBuilderFactory;
@Bean
public Step myStep() {
return this.stepBuilderFactory.get("myStep")
.tasklet(..) // or .chunk()
.build();
}
}
이 이유는 Spring Batch 4.3까지는 @EnableBatchProcessing
에서 애플리케이션 컨텍스트에 transactionManager 빈을 노출시켰다.
이럴 경우 사용자가 정의한 transactionManager와 충돌할 수 있는 문제가 발생한다. 따라서 @EnableBatchProcessing
이 더이상 애플리케이션 컨텍스트에서 transactionManager 빈을 노출시키지 않는다.
그리고 코드도 아래와 같은 형태로 변했다.
// Sample with v5
@Configuration
@EnableBatchProcessing
public class MyStepConfig {
@Bean
public Tasklet myTasklet() {
return new MyTasklet();
}
@Bean
public Step myStep(JobRepository jobRepository, Tasklet myTasklet, PlatformTransactionManager transactionManager) {
return new StepBuilder("myStep", jobRepository)
.tasklet(myTasklet, transactionManager) // or .chunk(chunkSize, transactionManager)
.build();
}
}
위와 같은 문제에 대해 자세하게 확인하고 싶다면 해당 이슈와 이 이슈를를 확인해보면 좋다.
Spring Batch5의 바뀐점은 아직도 많이 있지만 짧게 이정도만 정리했다.
더 자세한 내용을 확인하고 싶다면 공식문서를 참고하면 좋다.