3. The Domain Language of Batch
경험 많은 배치 아키텍트는, 스프링 배치에서 사용되는 배치 처리의 전반적인 개념이 익숙하고 편안해야 한다. “잡(Job)” 및 “스텝(Step)”과 아이템리더(ItemReader)
및 아이템라이터(ItemWriter)
라는 개발자에게 제공되는 처리 단위가 있다. 그러나 스프링의 패턴들, 오퍼레이션(operation), 템플릿(template), 콜백(callback) 및 관용구를 익히면 다음과 같은 이점 있다.
- 명확한 관심사 분리를 준수하는 비율 크게 향상.
- 명확하게 기술된 아키텍처 계층 및 인터페이스로 제공되는 서비스.
- 신속하게 채택하고 즉시 사용할 수 있는 간단한 기본 구현체들.
- 대폭 향상된 확장성.
다음 다이어그램은 수십 년 동안 사용된 배치 아키텍처를 단순화한 것이다. 배치 처리의 도메인 언어를 구성하는 구성 요소에 대한 개요이다. 이 아키텍처 프레임워크는 지난 몇 세대의 플랫폼(메인프레임의 코볼, 유닉스의 C, 이제 어디서나 사용하는 자바)에서 수십 년간 구현을 통해 입증된 청사진이다. JCL 및 코볼 개발자는 C, C# 및 자바 개발자만큼 개념에 익숙할 것이다. 스프링 배치는 매우 복잡한 요구 사항을 해결하기 위해, 인프라스트럭처 및 확장 기능으로 단순하거나 복잡한 배치 애플리케이션 생성을 처리하는 데 사용되는, 강력하고 유지 관리 가능한 시스템에서 일반적으로 발견되는 계층, 구성 요소 및 기술 서비스의 물리적 구현을 제공한다.
이미지 3. 배치 구성 요소
앞의 다이어그램은 스프링 배치의 도메인 언어를 구성하는 주요 개념들을 보여준다. 잡(Job)
에는 하나 이상의 스텝(Step)이 있으며 각 스텝에는 정확히 하나의 아이템리더(ItemReader)
, 하나의 아이템프로세서(ItemProcessor)
및 하나의 아이템라이터(ItemWriter)
가 있다. 잡을 시작 하고(잡런처(JobLauncher)
사용) 현재 실행 중인 프로세스에 대한 메타데이터를 잡리포지터리(JobRepository)
에 저장해야 한다.
3.1. Job
이 절에서는 배치 잡(Job)의 개념을 설명한다. 잡은 전체 배치 프로세스를 캡슐화하는 엔터티(entity)이다. 다른 스프링 프로젝트와 마찬가지로 잡은 XML 구성 파일 또는 자바 기반 구성과 함께 사용된다. 이 구성을 “잡 구성”이라 한다. 잡은 다음 다이어그램과 같이, 전체 구조에서 최상위 계층이다.
이미지 4. 잡 계층
스프링 배치에서, 잡
은 단순히 스텝
인스턴스의 컨테이너이다. 논리적 흐름에 맞는 여러 스텝를 결합하고 재시작 가능성과 같은, 모든 스텝에 전반적인 프로퍼티를 구성한다. 잡 구성에는 다음 내용이 포함된다.
- 잡 이름.
스텝
인스턴스의 정의 및 순서 지정.- 잡의 재시작 여부.
스프링 배치는 잡 위에 몇 가지 표준 기능을 생성하는 심플잡(SimpleJob)
클래스의 형태로 잡(Job)
인터페이스의 기본적인 구현(implementation)을 제공한다. 자바 기반 구성을 사용하는 경우, 다음 예제와 같이 빌더 모음을 잡
인스턴스화에 사용할 수 있다:
@Bean
public Job footballJob(JobRepository jobRepository) {
return new JobBuilder("footballJob", jobRepository)
.start(playerLoad())
.next(gameLoad())
.next(playerSummarization())
.build();
}
그러나, XML 구성을 사용하는 경우, 배치 네임스페이스는 이를 직접 인스턴스화할 필요성을 추상화한다. 대신 다음 예제와 같이 <job>
엘리먼트(element)를 사용할 수 있다:
<job id="footballJob">
<step id="playerload" next="gameLoad"/>
<step id="gameLoad" next="playerSummarization"/>
<step id="playerSummarization"/>
</job>
3.1.1. JobInstance
잡인스턴스(JobInstance)
는 잡 실행을 개념적으로 나타낸 것이다. 이전 다이어그램의 EndOfDay
잡
과 같이, 하루가 끝날 때 한 번 실행되어야 하는 배치 잡을 생각해보자. EndOfDay
잡은 하나 있지만 각 개별 실행을 각각 추적해야 한다. 이 잡의 경우, 하루에 단 하나의 논리적 잡인스턴스가 있다. 예를 들어, 1월 1일 실행, 1월 2일 실행 등이 있다. 1월 1일 실행이 처음에 실패하고 다음날 재실행되면, 여전히 1월 1일 실행이어야 한다 (일반적으로 처리 중인 데이터와도 일치한다. 즉, 1월 1일 실행이 1월 1일 데이터를 처리함을 의미한다.). 따라서, 각 잡인스턴스는 여러 번 실행될 수 있으며(잡익스큐션(JobExecution)
은 이 장의 뒷부분에서 자세히 설명함), 주어진 시간에 하나의 잡인스턴스(특정 잡
과 잡파라미터(JobParameters)
)만 실행할 수 있다.
잡인스턴스
의 정의는 로드할 데이터와 전혀 관련이 없다. 데이터가 로드되는 방식을 결정하는 것은 전적으로 아이템리더(ItemReader)
의 구현에 달려 있다. 예를 들어, EndOfDay
시나리오에서 데이터가 속한 유효 날짜(effective date)
또는 일정 날짜(schedule date)
를 나타내는 데이터 컬럼이 있을 수 있다. 따라서 1월 1일 실행은 1일의 데이터만 로드하고, 1월 2일 실행은 2일의 데이터만 사용한다. 이 결정은 비즈니스적인 결정일 가능성이 높으므로 아이템리더(ItemReader)
가 결정한다. 그러나 동일한 잡인스턴스
를 사용하면 이전 실행 “상태” (즉, 이 장의 뒷부분에서 설명하는 익스큐션컨텍스트(ExecutionContext)
)의 사용여부가 결정된다. 새로운 잡인스턴스를 사용한다는 것은 “처음부터 시작”을 의미하고 기존 인스턴스를 사용한다는 것은 일반적으로 “중단한 부분부터 시작”을 의미한다.
3.1.2. JobParameters
잡인스턴스
와 그것이 잡
과 어떻게 다른지에 대해 논의한 후 자연스럽게 물어볼 질문은 다음과 같다: “하나의 잡인스턴스와 다른 잡인스턴스는 어떻게 구별되나?” 답은: 잡파라미터(JobParameters)
이다. 잡파라미터
객체는 배치 잡을 시작하는 데 사용되는 파라미터 집합을 가지고 있다. 다음 이미지와 같이 식별을 위해 사용하거나 실행 중에 참고 데이터로 사용할 수도 있다:
이미지 5. 잡파라미터
앞의 예에서, 1월 1일에 대한 인스턴스와 1월 2일에 대한 두 개의 인스턴스가, 실제로는 하나의 잡이지만, 두 개의 잡파라미터 객체가 있다: 하나는 2017-01-01의 잡파라미터로 시작됐고 다른 하나는 2017-01-02의 잡파라미터로 시작됐다. 따라서 다음과 같이 정의할 수 있다: 잡인스턴스(JobInstance) = 잡(Job) + 잡파라미터(JobParameter)
. 이를 통해 개발자는 전달되는 파라미터를 제어하므로 잡인스턴스가 정의되는 방식을 효과적으로 제어할 수 있다.
잡인스턴스
를 식별하는 데 모든 잡파라미터가 필요한 것은 아니다. 그러나, 프레임워크는잡인스턴스
식별(identity)에 관련없는 파라미터를 사용하여잡
을 나타낼 수도 있다.
3.1.3. JobExecution
잡익스큐션(JobExecution)
은 잡을 실행하려는 단일 시도의 기술적 개념을 나타낸다. 익스큐션은 실패 또는 성공으로 종료될 수 있지만, 해당 익스큐션의 잡인스턴스(JobInstance)
가 성공적하지 않으면, 완료된 것으로 간주되지 않는다. 앞에서 설명한 EndOfDay 잡
을 예로 사용하여, 처음 실행했을 때 실패한 2017년 1월 1일의 잡인스턴스
를 생각해 보자. 첫 번째 실행(2017-01-01)과 동일한 잡파라미터를 사용하여 재실행하면 새 잡익스큐션
이 생성된다. 그러나 여전히 하나의 잡인스턴스
만 있다.
잡은 잡이 무엇이고 어떻게 실행되는지 정의하며, 잡인스턴스는 잡익스큐션을 함께 그룹화하는 객체이며, 올바른 재시작 시맨틱(semantics)을 가능하게 한다. 그러나 잡익스큐션은 실행 중에 실제로 발생한 일에 대한 저장 메커니즘이며 다음 표와 같이 제어하고 유지해야 하는 더 많은 프로퍼티를 가지고 있다:
테이블 1. 잡익스큐션 프로퍼티
프로퍼티 | 정의 |
---|---|
Status | 실행 상태를 나타내는 BatchStatus 객체. 실행 중에는 BatchStatus#STARTED 이다. 실패하면 BatchStatus#FAILED 이다. 성공적으로 완료되면 BatchStatus#COMPLETED 이다. |
startTime | 실행이 시작된 현재 시스템 시간을 나타내는 java.time.LocalDateTime 이다. 잡이 아직 시작되지 않은 경우 이 필드는 비어 있다. |
endTime | 성공 여부에 관계없이, 실행이 완료된 현재 시스템 시간을 나타내는 java.time.LocalDateTime 이다. 잡이 아직 완료되지 않은 경우 필드가 비어 있다. |
exitStatus | 실행 결과를 나타내는, ExitStatus 이다. 호출자에게 반환되는 종료 코드가 포함되어 있기 때문에 가장 중요하다. 자세한 내용은 5장을 참고하자. 잡이 아직 완료되지 않은 경우 필드가 비어 있다. |
createTime | 잡익스큐션이 처음 지속될 때 현재 시스템 시간을 나타내는 java.time.LocalDateTime 이다. 잡이 아직 시작되지 않았을 수 있지만(따라서 시작 시간이 없음), 잡 레벨에서 익스큐션컨텍스트(ExecutionContexts)를 관리하기 위해 프레임워크에 필요한 createTime 이 항상 있다. |
lastUpdated | 잡익스큐션 이 지속된 마지막 시간을 나타내는 java.time.LocalDateTime 이다. 잡이 아직 시작되지 않은 경우 이 필드는 비어 있다. |
executionContext | 실행 간에 유지되어야 하는 사용자 데이터가 포함된 “프로퍼티 모음”이다. |
failureExceptions | 잡을 실행하는 동안 발생한 예외 목록이다. 잡이 실패하는 동안 둘 이상의 예외가 발생하는 경우 유용할 수 있다. |
이러한 프로퍼티는 지속되며 실행 상태를 결정할 수 있기 때문에 중요하다. 예를 들어, 01-01에 대한 EndOfDay
잡이 오후 9시에 실행되고 9시 30분에 실패하면, 배치 메타데이터 테이블에 다음 항목이 생성된다:
테이블 2. BATCH_JOB_INSTANCE
JOB_INST_ID | JOB_NAME |
---|---|
1 | EndOfDayJob |
테이블 3. BATCH_JOB_EXECUTION_PARAMS
JOB_EXECUTION_ID | TYPE_CD | KEY_NAME | DATE_VAL | IDENTIFYING |
---|---|---|---|---|
1 | DATE | schedule.Date | 2017-01-01 | TRUE |
테이블 4. BATCH_JOB_EXECUTION
JOB_EXEC_ID | JOB_INST_ID | START_TIME | END_TIME STATUS | |
---|---|---|---|---|
1 | 1 | 2017-01-01 21:00 | 2017-01-01 21:30 | FAILED |
포맷과 명확성을 맞추기 위해 컬럼명이 축약되거나 제거됐을 수 있다.
이제 잡이 실패했으므로, “배치 윈도우”가 지금 닫혔고, 문제를 확인하는 데 밤을 샛다고 가정하자. 또한 배치 윈도우가 오후 9시에 시작한다고 가정하고, 잡이 01-01에 대해 재시작되어 잡이 중단된 지점부터 시작하여 9시 30분에 성공적으로 완료됐다. 지금은 다음 날이기 떄문에, 01-02 잡도 실행해야 하며, 9시 31분에 바로 시작되어 10시 30분에 정상적으로 한 시간 동안 완료됐다. 두 잡이 동일한 데이터에 접근하려고 시도하여 데이터베이스 레벨에서 잠금 문제를 일으킬 가능성이 없는 한 하나의 잡인스턴스를 차례로 시작해야 한다는 요구 사항은 없다. 잡을 실행해야 하는 시기를 결정하는 것은 전적으로 스케줄러(scheduler)에게 달려 있다. 그것들은 별개의 잡인스턴스이기 때문에 스프링 배치는 동시에 실행되는 것을 막으려 하지 않는다(다른 잡인스턴스가 이미 실행 중일 때 동일한 잡인스턴스를 실행하려고 하면 잡익스큐션올레디러닝익셉션(JobExecutionAlreadyRunningException)
이 발생한다). 다음 표와 같이 잡인스턴스 및 잡파라미터 테이블에 추가 항목이 하나 있고 잡익스큐션 테이블에 두 개의 추가 항목이 있어야 한다.
테이블 5. BATCH_JOB_INSTANCE
JOB_INST_ID | JOB_NAME |
---|---|
1 | EndOfDayJob |
2 | EndOfDayJob |
테이블 6. BATCH_JOB_EXECUTION_PARAMS
JOB_EXECUTION_ID | TYPE_CD | KEY_NAME | DATE_VAL | IDENTIFYING |
---|---|---|---|---|
1 | DATE | schedule.Date | 2017-01-01 00:00:00 | TRUE |
2 | DATE | schedule.Date | 2017-01-01 00:00:00 | TRUE |
3 | DATE | schedule.Date | 2017-01-02 00:00:00 | TRUE |
테이블 7. BATCH_JOB_EXECUTION
JOB_EXEC_ID | JOB_INST_ID | START_TIME | END_TIME STATUS | |
---|---|---|---|---|
1 | 1 | 2017-01-01 21:00 | 2017-01-01 21:30 | FAILED |
2 | 1 | 2017-01-02 21:00 | 2017-01-02 21:30 | COMPLETED |
3 | 2 | 2017-01-02 21:31 | 2017-01-02 22:29 | COMPLETED |
포맷과 명확성을 맞추기 위해 컬럼명이 축약되거나 제거됐을 수 있다.
3.2. Step
스텝(Step)
은 배치 잡의 독립적이고, 순차적인 단계를 캡슐화하는 도메인 객체이다. 따라서, 모든 잡
은 하나 이상의 스텝으로 구성된다. 스텝
에는 배치 프로세스를 정의하고 제어하는 데 필요한 모든 정보가 포함된다. 주어진 스텝
의 내용은 잡
을 작성하는 개발자의 생각을 따르기 때문에 위 설명은 조금 모호하다. 스텝
은 개발자가 원하는 만큼 간단하거나 복잡할 수 있다. 간단한 스텝은 파일에서 데이터베이스로 데이터를 로드할 수 있으며, 코드가 거의 또는 전혀(사용된 구현에 따라 다름) 필요하지 않다. 복잡한 스텝
에는 프로세스의 일부로 적용되는 복잡한 비즈니스 규칙이 있을 수 있다. 잡
과 마찬가지로 스텝
에는 다음 이미지와 같이 고유한 잡익스큐션(JobExecution)
과 상관 관계가 있는 개별 스텝익스큐션(StepExecution)
이 있다:
이미지 6. 스텝과 잡 계층
3.2.1. StepExecution
스텝익스큐션(StepExecution)
은 스텝
을 실행하려는 하나의 시도를 나타낸다. 잡익스큐션
과 유사하게 스텝이 실행될 때마다 새 스텝익스큐션
이 생성된다. 그러나, 이전 스텝이 실패하여 스텝이 실행되지 않으면 실행이 지속되지 않는다. 스텝익스큐션
은 스텝
이 실제로 시작된 경우에만 생성된다.
스텝의 실행은 스텝익스큐션(StepExecution)
클래스의 객체로 표시된다. 각 실행에는 해당 스텝 및 잡익스큐션
에 대한 참조와 커밋 및 롤백 횟수, 시작 및 종료 시간과 같은 트랜잭션 관련 데이터가 포함된다. 또한 각 스텝의 익스큐션에는 재시작하는 데 필요한 통계 또는 상태 정보와 같이 개발자가 배치 실행 간에 유지해야 하는 모든 데이터가 포함된 익스큐션컨텍스트(ExecutionContext)
가 포함된다. 다음 표에는 스텝익스큐션(StepExecution)
의 프로퍼티가 나열되어 있다.
테이블 8. StepExecution 프로퍼티
Property | Definition |
---|---|
Status | 실행 상태를 나타내는 BatchStatus 객체이다. 실행 중 상태는 BatchStatus.STARTED 이다. 실패하면 상태는 BatchStatus.FAILED 이다. 성공적으로 완료되면 상태는 BatchStatus.COMPLETED 이다. |
startTime | 실행된 현재 시스템 시간을 나타내는 java.time.LocalDateTime 스텝이 아직 시작되지 않은 경우 이 필드는 비어 있다. |
endTime | 성공 여부에 관계없이 실행이 완료된, 현재 시스템 시간을 나타내는 java.time.LocalDateTime 이다. 스텝이 아직 종료되지 않은 경우 이 필드는 비어 있다. |
exitStatus | 실행 결과를 나타내는 ExitStatus 이다. 호출자에게 반환되는 종료 코드가 포함되어 있기 때문에 가장 중요하다. 자세한 내용은 5장을 참조해보자. 잡이 아직 종료되지 않은 경우 이 필드는 비어 있다. |
executionContext | 실행 간에 유지되어야 하는 사용자 데이터가 포함된 “프로퍼티 모음”이다. |
readCount | 성공적으로 읽은 항목의 수이다. |
writeCount | 성공적으로 작성된 항목의 수이다. |
commitCount | 이 실행을 위해 커밋된 트랜잭션 수이다. |
rollbackCount | 스텝에서 제어하는 비즈니스 트랜잭션이 롤백된 횟수이다. |
readSkipCount | 읽기 실패 횟수로, 스킵 아이템이 발생했다. |
processSkipCount | 프로세스 실패 횟수로, 스킵 아이템이 발생했다. |
filterCount | 아이템프로세서(ItemProcessor)에 의해 “필터링”된 항목의 수이다. |
writeSkipCount | 쓰기 실패 횟수로, 스킵 아이템이 발생했다. |
3.3. ExecutionContext
익스큐션컨텍스트(ExecutionContext)
는 개발자에게 스텝익스큐션(StepExecution)
객체 또는 잡익스큐션(JobExecution)
객체의 상태를 저장할 장소를 제공하기 위한 프레임워크에 의해 지속되고 제어되는 키/값 쌍의 모음(쿼츠(Quartz)에 익숙한 사람들에게는, 잡데이터맵(JobDataMap)
과 유사함)을 나타낸다. 가장 좋은 사용 예는 재시작을 용이하게 하는 것이다. 플랫 파일 입력을 예로 사용하여, 각 로우을 처리하는 동안 프레임워크는 커밋 지점에서 익스큐션컨텍스트(ExecutionContext)
를 주기적으로 유지한다. 이렇게 하면 실행 중 치명적인 오류가 발생하거나 전원이 꺼지더라도 아이템리더(ItemReader)
가 상태를 저장할 수 있다. 다음 예제와 같이 현재 읽은 줄수를 컨텍스트에 입력하면 나머지는 프레임워크가 수행한다:
executionContext.putLong(getKey(LINES_READ_COUNT), reader.getPosition());
잡(Job)
절의 EndOfDay
예제를 예로 사용하여 파일을 데이터베이스로 로드하는 loadData
라는 스텝(Step)이 있다고 가정하자. 첫 번째 실행 실패 후, 메타데이터 테이블은 다음 예와 같다.
테이블 9. BATCH_JOB_INSTANCE
JOB_INST_ID | JOB_NAME |
---|---|
1 | EndOfDayJob |
테이블 10. BATCH_JOB_EXECUTION_PARAMS
JOB_INST_ID | TYPE_CD | KEY_NAME DATE_VAL | |
---|---|---|---|
1 | DATE | schedule.Date | 2017-01-01 |
테이블 11. BATCH_JOB_EXECUTION
JOB_EXEC_ID | JOB_INST_ID | START_TIME | END_TIME STATUS | |
---|---|---|---|---|
1 | 1 | 2017-01-01 21:00 | 2017-01-01 21:30 | FAILED |
테이블 12. BATCH_STEP_EXECUTION
STEP_EXEC_ID | JOB_EXEC_ID | STEP_NAME | START_TIME END_TIME | STATUS | |
---|---|---|---|---|---|
1 | 1 | loadData | 2017-01-01 21:00 | 2017-01-01 21:30 | FAILED |
테이블 13. BATCH_STEP_EXECUTION_CONTEXT
STEP_EXEC_ID | SHORT_CONTEXT |
---|---|
1 | {piece.count=40321} |
위 사례에서, 스텝(step)
은 30분 동안 실행되었고, 파일의 로우을 나타내는, 40,321개의 “piece”을 처리했다. 이 값은 프레임워크에서 각 커밋(Commit) 직전에 업데이트되며 익스큐션컨텍스트(ExecutionContext)
에 해당하는 아이템의 여러 로우을 포함할 수 있다. 커밋 전 알림을 받으려면 다양한 스텝리스너(StepListener)
의 구현체(implementations)(또는 아이템스트림(ItemStream)
) 중 하나가 필요한데, 이에 대해서는 이 가이드의 뒷부분에서 자세히 설명한다. 이전 예제와 마찬가지로, 다음 날 잡
이 재시작된다고 가정해보자. 재시작하면, 마지막 실행의 익스큐션컨텍스트(ExecutionContext)
값이 데이터베이스에서 재구성된다. 아이템리더(ItemReader)
가 열리면, 다음 예제와 같이 컨텍스트에 저장된 상태가 있는지 확인하고 거기에서 초기화할 수 있다:
if (executionContext.containsKey(getKey(LINES_READ_COUNT))) {
log.debug("Initializing for restart. Restart data is: " + executionContext);
long lineCount = executionContext.getLong(getKey(LINES_READ_COUNT));
LineReader reader = getReader();
Object record = "";
while (reader.getPosition() < lineCount && record != null) {
record = readLine();
}
}
이 상황에서, 앞의 코드가 실행된 후, 현재 줄은 40,322이므로 스텝
이 중단된 위치에서 재시작된다. 실행중 유지해야하는 통계 정보에 익스큐션컨텍스트(ExecutionContext)
를 사용할 수도 있다. 예를 들어, 플랫 파일에 여러 로우에 걸쳐 처리해야 할 일감들이 포함되어 있다면, (읽은 라인의 수와는 다른)처리된 일감의 수를 저장하는 것이 필요할 수 있으며, 그렇게 함으로써 스텝
이 끝날 때 처리된 주문 총 수를 본문에 포함하여 이메일을 보낼 수 있다. 프레임워크는 각 잡인스턴스
의 정확한 범위를 지정할 수 있도록 개발자를 위해 그것에 대한 저장을 처리한다. 기존 익스큐션컨텍스트(ExecutionContext)
를 사용해야 하는지를 아는 것은 매우 어려울 수 있다. 예를 들어, 위의 EndOfDay
예를 사용하여 01-01 실행이 두 번째로 재시작되면, 프레임워크는 동일한 잡인스턴스
임을 인식하고 각 스텝별로, 익스큐션컨텍스트(ExecutionContext)
를 데이터베이스에서 가져와 전달하고, 스텝 자체(스텝익스큐션(StepExecution)
의 일부로)에서 처리한다. 반대로, 01-02 실행의 경우, 프레임워크는 다른 인스턴스임을 인식하므로, 빈 컨텍스트를 스텝에 전달한다. 프레임워크는 개발자를 위해 올바른 시간에 상태가 제공되도록 하는 것과 같은 여러 유형의 결정을 많이 만들어낸다. 주어진 시간에 스텝익스큐션(StepExecution)
당 정확히 하나의 익스큐션컨텍스트(ExecutionContext)
가 존재한다는 점도 중요하다. 익스큐션컨텍스트(ExecutionContext)
의 클라이언트는 공유 키스페이스(keyspace)를 생성하므로, 주의해야 한다. 따라서, 값을 입력할 때 데이터를 덮어쓰지 않도록 주의해야 한다. 그러나, 스텝
은 컨텍스트에 데이터를 저장하지 않으므로 프레임워크에 악영향을 줄 방법은 없다.
잡익스큐션(JobExecution)
당 하나 이상의 익스큐션컨텍스트(ExecutionContext)
가 있을 수 있고, 스텝익스큐션(StepExecution)
마다는 하나씩 있다. 예를 들어 다음 코드 스니펫을 보자:
ExecutionContext ecStep = stepExecution.getExecutionContext();
ExecutionContext ecJob = jobExecution.getExecutionContext();
// ecStep은 ecJob과 같지 않다.
주석에서 언급했듯이, ecStep은 ecJob과 같지 않다. 그것들은 서로 다른 두 개의 익스큐션컨텍스트(ExecutionContext)
이다. 스텝으로 범위가 지정된 것은 스텝의 모든 커밋 지점에 저장되는 반면, 잡으로 범위가 지정된 것은 모든 스텝 실행 사이에 저장된다.
3.4. JobRepository
잡리포지터리(JobRepository)
는 앞서 언급한 개념 대한 영속성(persistence) 메커니즘이다. 그것은 잡런처(JobLauncher)
, 잡
및 스텝
의 구현(implementations)을 위한 CRUD 작업을 제공한다. 잡이 처음 시작되면, 리포지터리에서 잡익스큐션(JobExecution)
을 얻는다. 또한, 실행 과정에서, 스텝익스큐션(StepExecution)
및 잡익스큐션(JobExecution)
구현은 리포지터리에 전달되어 유지된다. 스프링 배치 XML 네임스페이스는 다음 예제와 같이 <job-repository>
태그로 잡리포지터리 인스턴스 구성을 지원한다:
<job-repository id="jobRepository"/>
자바 구성을 사용할 때 @EnableBatchProcessing
어노테이션은 자동으로 구성되는 구성 요소 중 하나로 잡리포지터리
를 제공한다.
3.5. JobLauncher
잡런처(JobLauncher)
는 다음 예제와 같이, 주어진 잡파라미터(JobParameter)
집합으로 잡
을 시작하기 위한 간단한 인터페이스를 나타낸다:
public interface JobLauncher {
public JobExecution run(Job job, JobParameters jobParameters)
throws JobExecutionAlreadyRunningException, JobRestartException, JobInstanceAlreadyCompleteException, JobParametersInvalidException;
}
구현체(implementations)는 잡리포지터리에서 유효한 잡익스큐션을 얻고 잡을 실행할 것으로 예상된다.
3.6. ItemReader
아이템리더(ItemReader)
는 한 번에 한 아이템씩, 스텝
에 입력되는 검색을 나타내는 추상화(abstraction)이다. 아이템리더가 제공할 수 있는 아이템을 소진하면, 널(null)
을 반환한다. 아이템리더
인터페이스와 다양한 구현체(implementations)에 대한 자세한 내용은 Readers And Writers에서 확인할 수 있다.
3.7. ItemWriter
아이템라이터(ItemWriter)
는 한 번에 하나의 배치 또는 아이템 청크 단위, 스텝
의 출력을 나타내는 추상화이다. 일반적으로, 아이템라이터는 다음으로 받아야 하는 입력에 대해 알지 못하고 현재 호출에서 전달된 아이템만 알고 있다. 아이템라이터
인터페이스와 다양한 구현체(implementations)에 대한 자세한 내용은 Readers And Writers에서 확인할 수 있다.
3.8. ItemProcessor
아이템프로세서(ItemProcessor)
는 아이템의 비즈니스 처리를 나타내는 추상화이다. 아이템리더(ItemReader)
가 하나의 아이템을 읽고, 아이템라이터(ItemWriter)
가 하나의 아이템을 쓰는 동안, 아이템프로세서
는 변환하거나 다른 비즈니스 처리를 적용하기 위한 접근 포인트를 제공한다. 아이템을 처리하는 동안, 아이템이 유효하지 않은 것으로 확인되면, 널(null)
을 반환하여 아이템을 작성하지 않아야 함을 나타낸다. Readers And Writers에서 아이템프로세서
인터페이스에 대한 자세한 내용을 확인할 수 있다.
3.9. Batch Namespace
이전에 나열된 많은 도메인 개념은 스프링 어플리케이션컨텍스트(ApplicationContext)
에서 구성되어야 한다. 표준 빈(bean) 정의에서 사용할 수 있는 인터페이스 구현체(implementations)가 있지만, 다음 예제와 같이 구성을 쉽게 하기 위해 네임스페이스가 제공된다:
<beans:beans xmlns="http://www.springframework.org/schema/batch"
xmlns:beans="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/batch
https://www.springframework.org/schema/batch/spring-batch.xsd">
<job id="ioSampleJob">
<step id="step1">
<tasklet>
<chunk reader="itemReader" writer="itemWriter" commit-interval="2"/>
</tasklet>
</step>
</job>
</beans:beans>
배치 네임스페이스가 선언된 엘리먼트를 사용할 수 있다. 잡
구성 및 실행에서 잡 구성에 대한 자세한 내용을 확인할 수 있다. 스텝
구성에 대한 자세한 내용은 스텝 구성에서 찾을 수 있다.