상세 컨텐츠

본문 제목

4. 예제1: Spring Batch Job HelloWorld - In Memory Repository

Spring/SpringBatch

by husks 2016. 3. 31. 15:23

본문

반응형

예제는 기본적인 JobReposiotry, JobLauncher, TransactionManger, Job, Listener의 관계를 설명하기 위해 작성되었습니다.

 

보다 상세한 내용은 다음의 블로글을 참조하세요.

 

1. Spring Batch Basics

 

2. Understanding Job and Step Configuration in Spring Batch

 

 

예제의 각 파일에 대한 기본적인 설명은 다음과 같습니다 (소스 코드는 첨부 파일을 다운로드 받으세요)


1. config/spring-context.xml: Spring Batch Infrastructure 설정.


2. com.hjh.batch.HelloWroldTasklet: 'Spring Batch Hellow World Tasklet!'를 출력하는 첫번째 커스텀 Tasklet (Job을 구성하는 첫번째 Step).


3. com.hjh.batch.GoodbyeTasklet: "Goodbye Spring Batch!"를 출력하는 두번째 커스템 Tasklet (Job을 구성하는 두번째 Step).


4. com.hjh.batch.JobListener - 커스텀 JobExecutionListener 구현체.


5. com.hjh.batch.StepListener - 커스텀 StepExecutionListener 구현체로 HelloWorldTasklet 및 GoodbyeTasklet의 리스너로 등록.


6. com.hjh.batch.JobRuntime - 커스텀 Job 실행 클래스.


7. com.hjh.batch.Launcher - main() 메소드가 있는 클래스.


 

 

1. spring-context.xml 설정


 <beans xmlns="http://www.springframework.org/schema/beans"

xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance

xmlns:aop="http://www.springframework.org/schema/aop"

xmlns:tx="http://www.springframework.org/schema/tx

xmlns:batch="http://www.springframework.org/schema/batch"

xmlns:task="http://www.springframework.org/schema/task"

xmlns:context="http://www.springframework.org/schema/context"

xsi:schemaLocation="

    http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd

    http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.1.xsd

    http://www.springframework.org/schema/task

    http://www.springframework.org/schema/task/spring-task-3.1.xsd

    http://www.springframework.org/schema/batch http://www.springframework.org/schema/batch/spring-batch-2.1.xsd

    http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.1.xsd">

    

    <bean id="transactionManager"

class="org.springframework.batch.support.transaction.ResourcelessTransactionManager" />

     <!-- 1. Job Repository - IN-MEMORY Repository -->

    <bean id="jobRepository"

class="org.springframework.batch.core.repository.support.MapJobRepositoryFactoryBean">

<property name="transactionManager" ref="transactionManager" />

    </bean>

    

    <!-- 2. Launch Job from a Repository -->

    <bean id="jobLauncher" class="org.springframework.batch.core.launch.support.SimpleJobLauncher">

     <property name="jobRepository" ref="jobRepository" />

    </bean>

    

    <!-- 3. Defines 2 steps of a Job -->

    <bean id="helloTask" class="com.hjh.batch.HelloWorldTasklet" />

    

    <bean id="goodbyeTask" class="com.hjh.batch.GoodbyeTasklet" />

    

    <!-- 4. Register Job Listener -->

    <bean id="jobListener" class="com.hjh.batch.JobListener" />

    

    <!-- 5. Register Step Listener -->

     <bean id="stepListener" class="com.hjh.batch.StepListener" />

     

    <!-- 6. Finally Job Defined -->

    <batch:job id="simpleJob">    

     <batch:step id="helloStep" next="goodbyeStep">

     <batch:tasklet ref="helloTask" />    

     <batch:listeners>

<batch:listener ref="stepListener" />

</batch:listeners>

     </batch:step>

     <batch:step id="goodbyeStep">

     <batch:tasklet ref="goodbyeTask" />

     <batch:listeners>

<batch:listener ref="stepListener" />

</batch:listeners>

     </batch:step>

     <batch:listeners>

     <batch:listener ref="jobListener" />

     </batch:listeners>

    </batch:job>

    

    <!-- 7. Custom Job Launcher Class -->

    <bean id="runtime" class="com.hjh.batch.JobRuntime">

     <property name="jobLauncher" ref="jobLauncher" />

     <property name="job" ref="simpleJob" />

    </bean> 

      

</beans>



1. JobRepsitory를 설정합니다. 예제에서는 In-Memory persistent store을 사용합니다. 이때 TransactionManager로 ResourcelessTransactionManager를 사용합니다. 실제 프로덕션 확경에서는 jdbc persistent store 사용이 바람직합니다.

물론 비즈니스 환경에 문제가 없다면 in-momory persistent store를 사용하셔도 무방합니다.

 

2. 실제로 Job을 실행하기 위한 JobLauncher를 설정합니다. Job을 실행하기 위해 유효한 JobExecution 정보을 업데이트하기 위한 JobRepository를 셋팅합니다.

 

SpringBatch의 SimpleJobLauncher는 JobLauncher 인터페이스의 구현체로써, Job을 실행하기 위해 Spring Core 패키지의 TaskExecutor를 내부적으로 사용합니다. 디폴트로 SyncTaskExecutor가 사용되는데, launcher를 콜한 같은 Thread에서 Job이 실행된다는 의미입니다. 따라서, asynchronous(비동기적) Job 실행을 위해서는 비동기적 목적의 TaskExecutor(SimpleAsyncTaskExecutor)를 설정하여야 합니다.

 

3. Job을 구성하는 첫번째 Step인 HelloTasklet와 두번째 Step인 GoodbyeTasklet을 설정합니다. 예제에서는 ItemReader / ItemWriter를 사용하지 않음으로 Tasklet 인터페이스를 구현하였습니다.

 

첫번째 Step HelloTasklet이 성공적으로 종료하면, next element 설정에 의해 두번째 Step GoodbyeTasklet이 실행되게 설정합니다.

 

만약, 하나의 Step이라도 실패하게 되면, Job 실행은 실패하게 됩니다.

 

4. JobExecutionListener 인터페이스의 커스텀 구현체인 JobListener을 설정합니다.

 

5. StepExecutionListener 인터페이스의 커스텀 구현체인 StepListener을 설정합니다.

 

6. JobLauncher에 의해 실행될 Job을 구현합니다. 

    Job은 3번에서 설정된 두개의 Step으로 구성하며, 각각의 Step은 5번에서 설정된 리스너를 등록합니다.

    그리고, Job에도 4번에서 설정된 리스너를 등록합니다.


7. 최종적으로 Job을 메인메소드에서 실행하기 위한 커스텀 launcher를 설정합니다.

 


2. HelloWorldTasklet 작성


 package com.hjh.batch;

 

import org.apache.log4j.Logger;

import org.springframework.batch.core.StepContribution;

import org.springframework.batch.core.scope.context.ChunkContext;

import org.springframework.batch.core.step.tasklet.Tasklet;

import org.springframework.batch.repeat.RepeatStatus;

 

public class HelloWorldTasklet implements Tasklet {

 

private static final Logger LOGGER = Logger.getLogger(HelloWorldTasklet.class);

@Override

public RepeatStatus execute(StepContribution arg0, ChunkContext arg1)

throws Exception {

 

LOGGER.info("Spring Batch Hellow World Tasklet!");

 

 

return RepeatStatus.FINISHED;

}

 

}


Tasklet(Step)이 실행되었을때, 단순히 "Spring Batch Hellow World Tasklet! 메시지를 콘솔에 출력합니다.

리턴값으로 RepeatStatus.FINISHED 값이 설정되었습니다. 만약, RepeatStatus.CONTINUABLE이 셋팅되 되면 두 번째 Step으로 이동하지 않고 반복적으로 HelloWorldTasklet이 실행됩니다.

 


3. GoodbyeTasklet 작성


 package com.hjh.batch;

 

import org.apache.log4j.Logger;

import org.springframework.batch.core.StepContribution;

import org.springframework.batch.core.scope.context.ChunkContext;

import org.springframework.batch.core.step.tasklet.Tasklet;

import org.springframework.batch.repeat.RepeatStatus;

 

public class GoodbyeTasklet implements Tasklet{

private static final Logger LOGGER = Logger.getLogger(GoodbyeTasklet.class);

 

@Override

public RepeatStatus execute(StepContribution arg0, ChunkContext arg1)

throws Exception {

 

LOGGER.info("Goodbye Spring Batch!");

return RepeatStatus.FINISHED;

}

 

}


Tasklet(Step)이 실행되었을때, 단순히 "Goodbye Spring Batch!" 메시지를 콘솔에 출력합니다.

 

 

4. JobListener 작성


 package com.hjh.batch;

 

import org.apache.log4j.Logger;

import org.springframework.batch.core.JobExecution;

import org.springframework.batch.core.JobExecutionListener;

 

public class JobListener implements JobExecutionListener {

 

private static final Logger LOGGER = Logger.getLogger(JobListener.class);

@Override

public void afterJob(JobExecution exec) {

LOGGER.info(">>> Job Executed: " + exec.getJobInstance().getJobName() + " : Batch Status: " + exec.getStatus());

}

 

@Override

public void beforeJob(JobExecution exec) {

LOGGER.info(">>> Job To Be Executed: " + exec.getJobInstance().getJobName());

}

 

}


Job이 실행되기 전에 beforeJob()이 호출되며, Job 실행이 종료되면 afterJob이 호출됩니다.



5. StepListener 작성


 package com.hjh.batch;

 

import org.apache.log4j.Logger;

import org.springframework.batch.core.ExitStatus;

import org.springframework.batch.core.StepExecution;

import org.springframework.batch.core.StepExecutionListener;

 

public class StepListener implements StepExecutionListener{

 

private static final Logger LOGGER = Logger.getLogger(StepListener.class);

@Override

public ExitStatus afterStep(StepExecution exec) {

LOGGER.info("### Step Executed: " + exec.getStepName());

return null;

}

 

@Override

public void beforeStep(StepExecution exec) {

LOGGER.info("### Step To Be Executed: " + exec.getStepName());

}

 

}

 

Step이 실행되기 전에 beforeStep()이 호출되며, Step 실행이 종료되면 afterStep이 호출됩니다.

 

 

6. JobRuntime 작성 (커스텀 Job Launcher)

 

 package com.hjh.batch;

 

import org.apache.log4j.Logger;

import org.springframework.batch.core.Job;

import org.springframework.batch.core.JobExecution;

import org.springframework.batch.core.JobParameters;

import org.springframework.batch.core.JobParametersBuilder;

import org.springframework.batch.core.launch.JobLauncher;

 

public class JobRuntime {

private static final Logger LOGGER = Logger.getLogger(JobRuntime.class);

private JobLauncher jobLauncher;

private Job job;

public JobRuntime(){

}

public void setJobLauncher(JobLauncher jobLauncher){

this.jobLauncher = jobLauncher;

}

public void setJob(Job job){

this.job = job;

}

public void launch() throws Exception{

        

        JobParameters jobParameters = new JobParametersBuilder().addLong("batch-date",

                System.currentTimeMillis()).toJobParameters();

        JobExecution exec = jobLauncher.run(job, jobParameters);

        

        LOGGER.info("Exit Status: " + exec.getStatus());

}

}

 

메인 메소드에서 lauch() 메소드를 호출하면 Job 이 실행됩니다.

 

7. 실행

 

Job을 실행하는 방법에는 두가지가 있습니다.

첫번째는, 예제에서 사용된 것처럼 커스텀 런쳐를 만들어서 실행하는 방법입니다.

예제에서 다음과 같이 메인 메소드 코드를 확인하세요.

 

 public static void main(String[] args)

    {

 

        try {

         /**

          * Job 실행 방벙1

          * 직접 JobLauncher를 호출하여 실형하는 방법

          */

        

          Launcher.appContext = new ClassPathXmlApplicationContext(

          SPRING_CONTEXT_CONFIG_FILE_PATH);

 

          JobRuntime runtime = (JobRuntime) appContext.getBean("runtime");

          

          runtime.launch();           

                     

        }

        catch (Exception e) {

            LOGGER.info("Launcher has failed", e);

            System.exit(-1);

        }

    }

 

두번째는, CommandLineJobRunner을 사용하는 방법입니다.

CommandLineJobRunner의 main() 메소드는 두개의 arguements를 받는데, 첫번째는 sping application context file이며, 두번째는 등록된 job이 이름을 받습니다.

 

 CommandLineJobRunner.main(new String[]{"config/spring-context.xml", "simpleJob"});

 

8. 결과

 

결과에서 Job 실행 이전 이후 JobListener가 호출된 로그와, 각 Step 실행 이전 이후 StepListener가 호출된 로그를 확인해 보세요.

Job 종류 이후 Exit Status: COMPLETED가 출력된 것도 확인 하세요.

 

 2013-07-04 22:06:02,431 INFO [com.hjh.batch.JobListener] - >>> Job To Be Executed: simpleJob (JobListener.java:19) beforeJob

2013-07-04 22:06:02,469 INFO [org.springframework.batch.core.job.SimpleStepHandler] - Executing step: [helloStep] (SimpleStepHandler.java:133) handleStep

2013-07-04 22:06:02,487 INFO [com.hjh.batch.StepListener] - ### Step To Be Executed: helloStep (StepListener.java:21) beforeStep

2013-07-04 22:06:02,542 INFO [com.hjh.batch.HelloWorldTasklet] - Spring Batch Hellow World Tasklet! (HelloWorldTasklet.java:17) execute

2013-07-04 22:06:02,568 INFO [com.hjh.batch.StepListener] - ### Step Executed: helloStep (StepListener.java:14) afterStep

2013-07-04 22:06:02,662 INFO [org.springframework.batch.core.job.SimpleStepHandler] - Executing step: [goodbyeStep] (SimpleStepHandler.java:133) handleStep

2013-07-04 22:06:02,666 INFO [com.hjh.batch.StepListener] - ### Step To Be Executed: goodbyeStep (StepListener.java:21) beforeStep

2013-07-04 22:06:02,669 INFO [com.hjh.batch.GoodbyeTasklet] - Goodbye Spring Batch! (GoodbyeTasklet.java:17) execute

2013-07-04 22:06:02,676 INFO [com.hjh.batch.StepListener] - ### Step Executed: goodbyeStep (StepListener.java:14) afterStep

2013-07-04 22:06:02,690 INFO [com.hjh.batch.JobListener] - >>> Job Executed: simpleJob : Batch Status: COMPLETED (JobListener.java:13) afterJob

2013-07-04 22:06:02,696 INFO [org.springframework.batch.core.launch.support.SimpleJobLauncher] - Job: [FlowJob: [name=simpleJob]] completed with the following parameters: [{batch-date=1372943162216}] and the following status: [COMPLETED] (SimpleJobLauncher.java:121) run

2013-07-04 22:06:02,696 INFO [com.hjh.batch.JobRuntime] - Exit Status: COMPLETED (JobRuntime.java:37) launch


출처: http://willygwu2003.blog.me/130171511927

반응형

관련글 더보기

댓글 영역