SpringBatch에 external Configuration Class 검토-2

JAVA/SpringBatch|2020. 4. 23. 19:38

지난번 SpringBoot에서 SpringBatch를 동작시키는데, External Class들을 잡는데 생기는 문제점들이 있어서

 

지난번 글에 MANIFEST.MF에 org.springframework.boot.loader.JarLauncher 가 Main-Class 에 적혀 있고

실제 개발한 코드의 메인은 Main-Class에 적힌 JarLauncher가 호출해준다는 부분을 언급했습니다.

 

JarLauncher 코드를 보며 클래스로더를 봤을때는 "클래스로더로 커스텀으로 구성하던지 해야겠구나" 로 생각했는데

검색해보니 역시나 해결방법은 있었습니다.

 

org.springframework.boot.loader.JarLauncher 말고도 빌드된 jar파일을 보면 다른 클래스들이 함께 들어있는데

다른 여러 클래스들이 있지만 Launcher 구현체 는 WarLauncher와 PropertiesLauncher 두가지가 추가로 있습니다.

org.springframework.boot.loader.PropertiesLauncher 소스를 열어보니 처음 시도하던 -cp로 잡은 클래스패스와 BOOT-INF를 같은 클래스로더로 구성하는 방식은 아니지만 클래스패스 경로를 지원하는 설정을 통해 BOOT-INF와 별도로 설정한 클래스 패스 경로를 설정할 수 있도록 작성되어있습니다

 

그설정은 바로 "loader.path" 입니다.

저는 실행시 -Dload.path=userLib/ 형식으로 주거나 별도 설정 파일로 영역을 열어줄 예정입니다.

"loader.path"의 특이사항으로는 해당 영역의 클래스와 jar 그리고 리소스를 모두 클래스 패스에 한번에 잡아준다는 부분이며 해당 클래스패스에 있는 Configuration 클래스들도 Bean으로 잘 등록되는것을 확인했습니다.

 

물론 이 부분이 해결됬다고 하더라도 추가적으로 해야할 부분은 많이 남았습니다.

외부 클래스들을 클래스 패스로 제공하면 현재는 패키지가 동일한 클래스를 테스트 했지만

다른 패키지라면 componentScan을 어떻게 제공할 것인지

xml 설정은 어떻게 커버할 것인지 등.. 하나씩 시도해보고 

막히는 부분이나 기록할 부분이 있으면 기록을 남길 예정입니다.

(작성하다보니 이건 SpringBatch 라기보다는 SpringBoot 활용 관련 이슈군요..)

댓글()

SpringBatch에 external Configuration Class 검토

JAVA/SpringBatch|2020. 4. 10. 20:12

업무상

SpringBoot 베이스로 SpringBatch 위에 조금 레이어를 추가할 계획을 가지고 있는데

 

제품 base jar에(SpringBoot 자체에 레이어를 추가한 jar) 에

클래스 패스로 추가적인 클래스(외부 개발자 혹은 고객이 개발 및 선언한 configuration class나 기타등등..)

를 더해서 돌려보면 어떨까 싶어 테스트를 시도하고 있습니다.

 

의도 했던 부분은 base jar에 추가적인 클래스를 심어 돌리면 되겠지만

관리상 base jar는 그대로 두고 추가적인 클래스는 jar로 묶거나 클래스 자체로 두고

배치 실행시 클래스패스에 base jar와 추가적인 클래스 jar를 잡아 실행 시키면 되지 않을까?

를 생각했지만 의도처럼 동작하지 않았습니다.

 

먼저 테스트로 추가해봤던 클래스는 job의 선언이 들어있는 Configuration Class 인데요

 

클래스 패스로 base와 추가된 클래스를 둘다 묶고 돌렸지만 몇가지 이슈들 만났습니다.

(일단 SpringBoot버전은 1.5.22와 2.2.5 그리고 1.3을 조금 살펴봤습니다. 1.3은 구조가 조금 달랐었습니다)

 

먼저 "java -jar boot.jar" 로 실행 했던것을 "java -cp boot.jar:app.jar com.meteor.AppMain" 방식으로 실행을 해봤는데

(실제 파일이나 옵션을 많이 생략했습니다)

 

boot.jar 내에 있는 com.meteor.AppMain 클래스를 못찾는 문제가 생겼습니다.

 

그래서 boot.jar 를 열어보니 클래스를 못찾는 이유를 알게됬는데, 디렉토리 구조가 일반적인 jar의 구조와는 많이 달랐습니다.

원래 boot.jar에 클래스가 있어야하는 바로 com 디렉토리가 보여야하는데

디렉토리 구조는

BOOT-INF

META-INF

org

였습니다.

 

META-INF는 흔한 디렉토리이고

org는 제가 생성하지 않은 클래스들이 들어있는 디렉토리 였습니다

BOOT-INF의 경우에는 하위에 classes와 lib이 있는데 classes에는

작성한 클래스들 lib에는 의존성이 걸려있는 lib들이 있었습니다.

 

위의 "java -cp boot.jar:app.jar com.meteor.AppMain" 처럼 실행했을때

com.meteor.AppMain을 찾으려면 org처럼 jar내에 바로 com 부터 있어야하는데 BOOT-INF/classes에 있으니

못찾는게 당연했습니다.

 

그럼 "java -jar boot.jar"로 호출했을때는 com.meteor.AppMain를 어떻게 찾고 있는건가?

를 살펴봤습니다.

 

일반적으로 execuexecutable jar는 META-INF의 MANIFEST.MF에 Main-Class에 있는 메인 클래스를 실행하게 됩니다.

 

그래서 boot.jar에 META-INF의 MANIFEST.MF에 Main-Class에 있는 클래스는

com.meteor.AppMain이라고 적혀있길 기대했지만

"org.springframework.boot.loader.JarLauncher" 라는 모르는 클래스가 적혀있었습니다.

그리고 "com.meteor.AppMain"는 Main-Class 에 적혀있지 않고 Start-Class 에 적혀있었습니다.

 

결국 "java-jar boot.jar" 를 호출한다면 com.meteor.AppMain이 호출되는것이 아니라 

org.springframework.boot.loader.JarLauncher것이 호출되는 것이고

내부 과정을 거쳐서 com.meteor.AppMain가 호출되는것을 예상 할수 있습니다.

 

그럼 "org.springframework.boot.loader.JarLauncher"는 무엇이고 어떻게 AppMain이 호출되는가?

를 조금 살펴봤습니다.

 

JarLauncher는 ExecutableArchiveLauncher를 상속 받고 있고 

ExecutableArchiveLauncher는 Launcher를 상속받고 있습니다.

 

당연히 JarLauncher에 main()이 있고, main 로직에는 launch(String[])를 호출하고 있고

launch(String[])은 상위에서 구현한 부분이 없기에 결국 Launcher에 launch(String[])가 불리고 코드는 하단과 같습니다.

protected void launch(String[] args) throws Exception {
    JarFile.registerUrlProtocolHandler();
    ClassLoader classLoader = createClassLoader(getClassPathArchives());
    launch(args, getMainClass(), classLoader);
  }

 

getClassPathArchives()에서는 BOOT-INF/classes/ 와 BOOT-INF/lib/의 경로를 넘기고

createClassLoader(url[])을 통해 LaunchedURLClassLoader를 만들도록 되어있습니다.

LaunchedURLClassLoader는 일단 URLClassLoader을 상속 받고 있고 당연히 상식적이게도 SystemClassLoader를 parent로 연결 시켜주는식으로 되어있습니다.

 

그후, getMainClass에서 MANIFEST.MF에 Start-Class 에 클래스를 얻어 넘기고 

launch에서는 start클래스에 메인 클래스를 부르는 MainMethodRunner를 통해 호출합니다.

(MainMethodRunner는 그냥 리플렉션으로 main(String[])를 부르는..클래스 입니다)

 

여기까지만 살펴봤을때 "JarLauncher가 결국에 Start-Class에 클래스를 리플랙션으로 부른다"

에 흐름 정도는 볼 수 있었습니다.

 

아 그렇군 그럼 "java -cp boot.jar:app.jar com.meteor.AppMain" 가 아니라

"java -cp boot.jar:app.jar org.springframework.boot.loader.JarLauncher" 를 부르면 되겠군!

이라고 생각했지만 AppMain은 불리지만 문제가 있었습니다.

app.jar에 포함되어있는 내용은 job의 선언부 즉, configuration인데 이 클래스에 Bean들을 등록하다가

org.springframework.batch.core.Step 클래스를 못찾는 문제가 발생했습니다

"응? org.springframework.batch.core.Step은 그냥 boot.jar안에 lib에 Spring-batch쪽에 있는..건데..? 왜 못찾지?"

 

사실 위에 힌트가 있습니다

클래스 못찾는 문제니 당연히 클래스 로더 이슈(클래스로더가 잘못됬다는건 아닙니다, 대부분 사람이 문제죠) 였습니다.

 

현재 Configuration클래스는 위에 -cp로 잡았기 때문에 시스템 클래스로더에 물려있습니다.

그리고 org.springframework.batch.core.Step는 아까 JarLauncher가 만든 LaunchedURLClassLoader에 물려있습니다.

그리고 서로의 관계는 LaunchedURLClassLoader의 부모로 시스템 클래스 로더로 구성되어있죠

 

일반적인 클래스로더 구조 보통 상위 클래스 로더에 있는지 찾고 내려오는 구조입니다.

(일반적으로 상위 클래스 로더는 child를 알진 못합니다.)

 

즉 Thread에 ContextClassLoader는 LaunchedURLClassLoader로 설정 했으니

LaunchedURLClassLoader를 통해 Step이든 ConfigurationClass든 다 볼수 있는건 맞지만 

 

Step만 로딩 한다면, 시스템 클래스로더에는 없으니 내려와서 LaunchedURLClassLoader 에서 찾고

ConfigurationClass를 로드 할때는 시스템 클래스로더에 있으니 바로 로딩했을겁니다.

그런데 ConfigurationClass를 막상 돌려보니 안에 Step.class가 있고 ConfigurationClass를 로딩한 시스템 클래스로더로 Step.class를 로드하니 없어서 에러가 난것으로 보입니다.

 

 

쉽게 말하면 parent클래스 로더에서 parent클래스 로더에 있는 클래스(child의 클래스를 바라보는)가 하위를 바라보니 시스템 클래스로더는 없는 클래스니 에러난거죠, JobConfig에서 Step을 참조할때 LaunchedURLClassLoader 를 쓰면 되겠지만, 에러가나는 코드는 빈등록하다 에러난거라..

 

 

일단 현상황은 이정도 이며

 

해결 방법은 여러가지가 있을테지만 아직 어떤 방법이 좋을지는 고민중입니다.

BOOT-INF 안에 넣어서 한 클래스 로더에 물리는 방법이 있고

메인을 변경해서 클래스 로더를 Flat하게 커스텀 하는 방법도.. 있을것 같고..

 

추가로 정리할 내용이 생기면 업데이트 하도록 하겠습니다.

댓글()

org.springframework.batch.core.launch.NoSuchJobException: No job configuration with the name [longJob] was registered

JAVA/SpringBatch|2020. 4. 2. 20:04

SpringBatch의 활용 및 동작 파악을 위해 끄적 끄적 하고 있는데

 

Job List를 얻으려면 어떻게 해야 하나 살펴보니 여러가지 방법이 있지만

두가지를 활용해봤습니다.

 

첫번째 방법

Job Type에 대해 Injection을 이용하는 방법

 

두번째 방법은 

ListableJobLocator 였습니다.

 

첫번째 방법인 JobType은 List<? extends Job> 이나

Map<String, ? extends Job>//String은 Bean네임 로 인젝션을 받으면

Bean으로 등록된 Job들을 받을수 있었습니다.

 

두번째 방법인 ListableJobLocator는 getJobNames()로 Job의 Name List를 가져오거나

getJob(name)을 통해 Job 객체를 가져올수 있습니다.

하지만, 저처럼 별다른 설정을 하지 않으면 위와 같은 에러를 만날수 있습니다.

@Bean
    public Job longJob() throws DuplicateJobException {
        return jobBuilderFactory.get("longJob").start(longStep()).build();
    }

에러가 발생하는 이유는 JobRegistry에 등록을 하지 않았기 때문인데요

 

해결하는 방법도 다양하겠지만 두가지를 소개 하려고합니다.

 

첫번째 방법 Job을 Bean으로 등록하기전 JobRegistry에 등록

두번째 방법 JobRegistryBeanPostProcessor를 Bean으로 등록하여 Registry에 등록

 

첫번째 방법인 JobRegistry에 등록하기 위해서는 JobRegistry에 register(JobFactory) 메소드를 이용하여 등록할 수 있는데, JobFactory는 ApplicationContextJobFactory 혹은 ReferrenceJobFactory를 통해 등록 하면 됩니다.

 

ApplicationContextJobFactory은 JobName과 ApplicationContextFactory를 받아 Bean으로 등록된 Job을 생성하는 Factory이며(Job을 Bean으로 등록하는 와중에 ApplicationContextJobFactory를 활용한 등록은 불가능 합니다.)

ReferrenceJobFactory는 Job Instance를 받아 그대로 돌려주는 방식으로 동작하는 Factory로 Bean을 등록하는 와중에 활용 할 수 있습니다.

@Bean
    public Job longJob() throws DuplicateJobException {
        Job job = jobBuilderFactory.get("longJob").start(longStep()).build();

        ReferenceJobFactory factory = new ReferenceJobFactory(job);
        jobRegistry.register(factory);
        return job;
    }

다만 이 방법은 Job Bean 선언 마다 register를 불러야 하는 단점과 원하는 Job만 등록할 수 있다는 장점이 있겠습니다.

 

두번째 방법은 JobRegistryBeanPostProcessor를 활용하는 방법이 있습니다.

 

@Bean
	public JobRegistryBeanPostProcessor jobRegistryBeanPostProcessor(JobRegistry jobRegistry) {
		JobRegistryBeanPostProcessor jobRegistryBeanPostProcessor = new JobRegistryBeanPostProcessor();
		jobRegistryBeanPostProcessor.setJobRegistry(jobRegistry);
		return jobRegistryBeanPostProcessor;
	}

네 끝입니다.

Job마다 등록할 필요 없이 Job Type이 빈으로 등록될때 후처리로 자동으로 JobRegistry에 등록하게 됩니다.

 

 

등록을 하지 않아도 Job Type을 Injection으로 찾아 JobLauncher로 실행도 가능하지만

등록하지 않으면 JobLocator 뿐 아니라 JobOperator도 동작하지 않더군요

예외사항이 생길지 모르겠지만 런타임시 관리를 위해서는 필수로 보입니다.

 

 

댓글()

[SpringBatch] State

JAVA/SpringBatch|2020. 3. 25. 20:07

Flow 내부에 Step 및 정보들은 모두 State로 이루어져 있어서 State 클래스들은 어떻게 구성되었는지 볼겸 정리

  • [I] State
    • [AC] AbstractState
      • [C] StepState
        • [C] JsrStepState
      • [C] DecisionState
      • [C] FlowState
      • [C] SplitState
        • [C] JsrSplitState
      • [C] DelegateState
      • [C] EndState
        • [C] JsrEndState

State
State에 도메인 인터페이스

  • 메소드
    • FlowExecutionStatus handle(FlowExecutor) : 해당 State를 처리하는 메소드, 상태는 String을 반환할 수 있지만, 특정 동작 상태들은 상수로 정의되어있다.
    • isEndState() : 마지막 State라면 true 리턴, 계속 처리 해야한다면 false를 리턴

AbstractState
보통 추상클래스에 공통로직들이 있는데, State는 공통로직이 거의 없다.

StepState
Step을 wrapping한 State인 만큼 Step을 변수로 가지고 있다.

  • 변수
    • Step : 자신에 해당하는 Step을 변수로 가짐
  • 메소드
    • FlowExecutionStatus handle(FlowExecutor) : Step을 FlowExecutor를 통해 실행

DecisionState
JobExecutionDecider 를 Wrapping 하고 있는 State

  • 변수
    • JobExecutionDecider : FlowExecutionStatus를 반환하는 decider

FlowState
Flow을 wrapping한 State인 만큼 Flow을 변수로 가지고 있다.

  • 변수
    • Flow : 자신에 해당하는 Flow을 변수로 가짐

SplitState
Flow를 병렬 처리 할경우 사용

  • 변수
    • Collection<Flow> : Split에 해당하는 Flow들
    • TaskExecutor : Flow들을 실행하는데 활용되는 Executor
    • FlowExecutionAggregator : 실행 후 aggregation에 활용
  • 메소드
    • FlowExecutionStatus handle(FlowExecutor) : 가지고 있는 Flow들을 실행, task들을 모두 기다리고 마지막에 aggregation

DelegateState
State Proxy에 활용

EndState
Job의 종료 관련

댓글()

[Spring Batch] Flow & Step

JAVA/SpringBatch|2020. 3. 23. 19:41

[I] Flow

  • [C] SimpleFlow
    • [C] JsrFlow

Flow
Batch의 Flow 도메인 클래스이며, 순차 Step 실행에는 Flow가 관여하지 않지만, on 과 같은 더 복잡한 흐름 제어가 필요한 경우 Flow가 필요

  • 메소드
    • FlowExecution start(FlowExecutor) : Flow의 실행을 담당하는 메소드
    • FlowExecution resume(stateName, FlowExecutor) : 특정 State 부터 다시 실행하게 하는 메소드
    • Collection<State> getStates() : Flow에 속한 State를 모두 리턴하는 메소드, State는 handle 메소드를 가지며, FlowExeStatus를 리턴

 

SimpleFlow
종료의 상태는 마지막 State에 의존

  • 변수
    • startState : 시작점 State
    • transitionMap : StateTransition의 Map, Transition을 통해 다음 어떤것을 수행할지 나타낼수 있음
    • StateMap : State에 대한 Map
    • stateTransitions : Transition의 리스트
    • stateTransitionComparator : Transition 비교를 위한 클래스
  • 메소드
    • FlowExecution start(FlowExecutor) : 첫번째 Step부터 실행(resume 호출)
    • FlowExecution resume(stateName, FlowExecutor) : isFlowContinued를 반복해서 호출하며 State를 실행
    • isFlowContinued(State, FlowStatus, StepExe) : State의 상태를 판단하여, Flow를 더 실행할지 제어하는 메소드
    • nextState(stateName, FlowStatus, StepExe) : 다음 State를 구하는 메소드

 

JsrFlow
JSR-352의 로직을 구현한 Flow

 

[I] Step

  • [C] AbstractStep
    • [C] PartitionStep
      • [C] PartitionStep
    • [C] TaskletStep
      • [C] BatchletStep
    • [C] DecisionStep
    • [C] JobStep
    • [C] FlowStep

Step
Step 설정을 나타내는 배치 도메인 인터페이스

  • 메소드
    • isAllowStartIfComplete : Complete 더라도 재실행을 허용할지
    • getStartLimit : 동일 식별자로 실행될수 있는 횟수
    • execute(StepExecution) : Step 의 처리를 다루는 메소드

AbstractStep
Step에 공통처리로직을 담은 AbstractClass

  • 변수
    • CompositeStepExecutionListener : StepExecutionListener를 컴포지트로 가지고 있으며 Step의 선 후 단계에서 호출하는 컴포지트 리스너
    • JobRepository : Job의 메타 정보들을 담당
  • 메소드
    • open(ExecutionContext) : doExecute(stepExe)를 호출하기 전 호출
    • close(ExecutionContext) : doExecute(stepExe) 이후 finally에서 호출
    • [A] doExecute() : 실제 Step 실행을 위해 열어놓은 메소드
    • [A] doExecutionRelease() : doExecute(stepExe) 이후 finally에서 close이후 호출
    • [final] execute(StepExe) : Step에 실행을 다루는 메소드, open, close 및 doExecute()를 실행

PartitionStep
Partition 처리를 위한 Step, 결국 파티셔너를 통해 StepExecutio을 여러개로 만들어서 Executor를 통해 수행
Executor가 기본적으로는 Sync지만, 변경하면 parallel도 가능

  • 변수
    • StepExecutionSplitter : Step을 Split하는 전략을 다루는 클래스, Set split(StepExe, gridSize)
    • PartitionHandler : Collection handle(StepExecutionSplitter,StepExe)
    • StepExecutionAggregator : Aggregate의 전략을 다루는 클래스 aggregate(StepExe, Collection)
  • 메소드
    • doExecute() : TaskExecutorPartitionerHandler 기준으로, executor.execute(task)로 다 돌린 후, stepExeAggregator.aggregate를 통해 aggregate

TaskletStep
간단 실행을 위한 Tasklet을 다루는 TaskletStep, 반복이 가능하며, 각 호출 마다 트랜잭션으로 묶인다.

  • 변수

    • RepeatOperations : Step에 반복 여부를 처리하는 Operations
    • CompositeChunkListener : ChunkListener 들을 컴포지트로 가지고 있는 Listener, chunk 전후에 호출
    • StepInterruptionPolicy : step 호출시마다 종료되었는지를 체크하는 클래스
    • CompositeItemStream : ItemStream을 컴포지트로 가지고있는 클래스, Overide 한 open, close, AbstractStep에 execute()에서
    • PlatformTransactionManager : Step처리에 트랜잭션 제어를 위한 트랜잭션 매니져
    • TransactionAttribute : 에러시 롤백 할지 등의 전략을 제공하는 Attribute
  • 메소드

    • doExecute() : TaskExecutorPartitionerHandler 기준으로, executor.execute(task)로 다 돌린 후, stepExeAggregator.aggregate를 통해 aggregate

DecisionStep
JSR-352에 정의되어있는 DecisionStep이며, JSR-352에 있는것 모두 지원하는 것은 아님

  • 변수

    • Decider : 종료 상태를 결정, String decide(StepExe[])

JobStep
Job을 실행할 수 있도록 하는 Step, 파티셔닝 실행 및 병렬 실행 지원

  • 변수

    • Job : 호출할 Job
    • JobLauncher : Job 실행을 위한 Launcher
    • JobParametersExtractor : JobParam getJobParameters(Job, StepExe) 을 통해 JobParam을 구하는 클래스
  • 메소드

    • doExecute() : jobParam 생성, JobLauncher를 통해 job 실행

FlowStep
Flow 실행을 위한 Step
Step의 그룹핑 실행과 여러 Step들의 파티셔닝 등을 위한 Step
(FlowJob과 거의 코드가 비슷..)

  • 변수

    • Flow : 실행할 Flow
  • 메소드

    • doExecute() : FlowExecutor를 통한 Flow 실행

추후 State, Execution

'JAVA > SpringBatch' 카테고리의 다른 글

[SpringBatch] State  (0) 2020.03.25
[Spring] Spring Batch Reader Writer  (0) 2020.03.24
[Spring Batch] Job  (0) 2020.03.20
[Spring] Spring Batch Tasklet  (0) 2020.02.25
[Spring] Spring Batch Version History  (0) 2020.02.22

댓글()

[Spring Batch] Job

JAVA/SpringBatch|2020. 3. 20. 19:58

다시 Spring Batch를 분석해야할 필요성이 생겨서....
어떤 클래스 구조들을 가지고, 어떤 기능들 및 구현범위들을 제공하고 있는지 살펴보고 있습니다.
물론 일반 개발자들이 Job을 손대거나 커스터마이징 할 일은 잘 없겠지만..

  • [I] Job
    • [C] GroupAwareJob
    • [AC] AbstractJob
      • [C] SimpleJob
      • [C] FlowJob
        • [C] JsrFlowJob

Job
배치에서 Job을 표현하는 가장 상위 도메인 인터페이스, 재시작은 Step 단위가 아니라 Job 단위임을 isRestartable()을 통해 알수 있음

  • getJobParametersValidator() : JobParameter 값의 유효성 체크
  • getJobParametersIncrementer() : Job 실행시 새로운 파라미터를 만들경우(JobParametersIncrementer에 구현 내용은 실제로 JobParam을 받아 JobParam을 리턴하도록 되어있음)
  • isRestartable() : 재시작 여부

GroupAwareJob
배치명을 그룹명을 포함하여 활용할 경우, 발췌잡 -> 론뱅크.발췌잡
그룹명을 들고 있고, 메소드는 다 Job에 있는 것들을 delegate 하여 호출하는 방식


AbstractJob
추상 클래스이며, 공통 의존성들에 대해(JobRepository나 JobExecututionListener나..) 설정들에 대해 로직들이 기술되어있음
실제 대부분 모든 Job은 AbstractJob을 상속받아 구현한 구현체일것
Step 관련된 로직은 대부분 Abstract로 두어 구현한 Job에 따라 원하는 형태로 관리할 수 있도록 함

  • 변수
    • JobRepository : Job의 정보(Param 이나 메타정보)들을 얻거나, 상태를 업데이트 하는 repo
    • CompositeJobExecutionListener : Job 선후에 불릴 JobExecutionListener들을 등록받아 일괄로 불러주는 컴포지트 클래스
    • StepHandler : step의 실제 처리 로직(실행 및 재처리에 따른 처리 및 상태처리 등)을 담고 있는 핸들러
  • 메소드
    • [A] getStep(String) : 추상메소드로 둬서 Step을 어떻게 저장하고 관리할지는 위로 위임
    • [A] getStepNames() : 추상메소드로 둬서 Step을 어떻게 저장하고 관리할지는 위로 위임
    • [final] execute(JobExe) : Job의 메소드이며 핸들러 호출 및 Repo 호출 등에 대한 로직이 담겨 있음, final로 구현 내용을 바꾸지 못하도록 했고, 메소드에서는 doExecute()을 호출하도록 되어있기 때문에 구현 클래스에서는 Job실행은 doExecute()을 통해 구현
    • [final] handleStep(Step, JobExe) : step에 실행에 대한 메소드를 final로 내용을 변경하지 못하도록 했고, StepHandler를 변경함으로 내용을 변경할 수 있도록 제공
    • [A] doExecute(JobExe) : 구현 클래스에서 Job 실행 부분을 구현하도록 열어놓은 메소드

SimpleJob
Step을 순차적으로 실행하는 Job의 구현체
Step이 실패시 Job이 실패하며, 모든 Step이 Complete 될경우 Job이 Complete 된다.

  • 변수
    • ArrayList : Step을 ArrayList로 관리//Step이 그렇게 많지는 않겠지만, getStep은 O(n)
  • 메소드
    • doExecute(JobExe) : step을 handleStep()으로 호출, Completed가 아닐시 break

FlowJob
순차실행 보다는 Flow를 통한 복잡한 처리를 위한 JobClass
초기 작업에서(findSteps) Flow에 있는 Step들을 stepMap에 넣고 시작

  • 변수
    • Flow : 실행할 Flow, 내부에 여러 Step이 존재
    • Map<String,Step> : Flow내에 존재하는 Step을 파싱(findSteps())하여 저장
  • 메소드
    • findSteps(Flow,Map) : Flow에서 Step들의 정보들을 꺼내서 Map에 저장
    • doExecute(JobExe) : flow.start(FlowExecutor)

JsrFlowJob
FlowJob을 상속 JSR-352 명세에 FlowJob

'JAVA > SpringBatch' 카테고리의 다른 글

[SpringBatch] State  (0) 2020.03.25
[Spring] Spring Batch Reader Writer  (0) 2020.03.24
[Spring Batch] Flow & Step  (0) 2020.03.23
[Spring] Spring Batch Tasklet  (0) 2020.02.25
[Spring] Spring Batch Version History  (0) 2020.02.22

댓글()

[Spring] Spring Batch Tasklet

JAVA/SpringBatch|2020. 2. 25. 20:07

ETL이나 각종 기능들은 결국 Tasklet을 구현하여 제공하는 기능들이며

Tasklet은 execute(S,C) 메소드 만을 제공합니다.

 

/**
* Given the current context in the form of a step contribution, do whatever
* is necessary to process this unit inside a transaction. Implementations
* return {@link RepeatStatus#FINISHED} if finished. If not they return
* {@link RepeatStatus#CONTINUABLE}. On failure throws an exception.
* 
* @param contribution mutable state to be passed back to update the current
* step execution
* @param chunkContext attributes shared between invocations but not between
* restarts
* @return an {@link RepeatStatus} indicating whether processing is
* continuable. Returning {@code null} is interpreted as {@link RepeatStatus#FINISHED}
*
* @throws Exception thrown if error occurs during execution.
*/
@Nullable
RepeatStatus execute(StepContribution contribution, ChunkContext chunkContext) throws Exception;

결국 리턴이 RepeatStatus.FINISHED(혹은 null) 로 리턴되면 마치게 되고 RepeatStatus.CONTINUABLE 의 경우에는 execute를 다시 호출하게 됩니다

(리턴값을 RepeatStatus.CONTINUABLE로 계속 반환하면 무한히 돌겠죠..)

 

 

Spring Batch에서 Tasklet을 imple하여 제공하고 있는 클래스 및 interface는 아래와 같습니다.

 

  • [I] Tasklet
    • [C] MethodInvokingTaskletAdapter : POJO 메소드 호출을 Step 시점에 호출하기위한 wraps 클래스
    • [C] CallableTaskletAdapter : Callable을 Step 시점에 호출하기 위한 wraps 클래스
    • [C] ChunkOrientedTasklet : ChunkProvider(SimpleChunkProvier 기준으로 ItemReader) , ChunkProcessor(SimpleChunkProcessor 기준으로 ItemProcessor, ItemWriter)를 활용하는 Tasklet(ETL)
    • [I] StoppableTasklet : (3.0부터) stop() 메소드를 구현하도록 하는 인터페이스며, 프레임워크에서 JobOperator.stop 시 해당 메소드를 불러줍니다.
      • [C] BatchletAdapter : (3.0부터) Batchlet을 지원하는 Tasklet Batchlet은 arg가 없는 process와 stop 메소드가 있는 interface 입니다.
      • [C] SystemCommandTasklet : Command(Java가 아닌 별도 프로그램을 실행한다던지)를 위한 Tasklet

 

 

'JAVA > SpringBatch' 카테고리의 다른 글

[SpringBatch] State  (0) 2020.03.25
[Spring] Spring Batch Reader Writer  (0) 2020.03.24
[Spring Batch] Flow & Step  (0) 2020.03.23
[Spring Batch] Job  (0) 2020.03.20
[Spring] Spring Batch Version History  (0) 2020.02.22

댓글()

[Spring] Spring Batch Version History

JAVA/SpringBatch|2020. 2. 22. 19:39

https://docs.spring.io/spring-batch/docs/3.0.9.RELEASE/reference/html/whatsNew.html

https://docs.spring.io/spring-batch/docs/4.2.x/reference/html/whatsnew.html#whatsNew

추후 각 버전별 주요 사항들을 조금씩 정리해보려고 합니다.

'JAVA > SpringBatch' 카테고리의 다른 글

[SpringBatch] State  (0) 2020.03.25
[Spring] Spring Batch Reader Writer  (0) 2020.03.24
[Spring Batch] Flow & Step  (0) 2020.03.23
[Spring Batch] Job  (0) 2020.03.20
[Spring] Spring Batch Tasklet  (0) 2020.02.25

댓글()