Sunday, October 6, 2013

Spring Batch "Hello World" 1

Posted in Java by Tareq Abedrabbo on Friday May 23, 2008
This is an introductory tutorial to Spring Batch. It does not aim to provide a complete guide to the framework but rather to facilitate the first contact. Spring Batch is quite rich in functionalities, and this is basically how I started learning it. Keep in mind that we will only be scratching the surface.

Before we start

All the examples will have the lofty task of printing "Hello World!" though in different ways. They were developed with Spring Batch 1.0. I'll provide a Maven 2 project and I'll run the examples with Maven but of course it is not a requirement to work with Spring Batch.

Spring Batch in 2 Words

Fortunately, Spring Batch model objects have self-explanatory names. Let's try to enumerate the most important and to link them together:
A batch Job is composed of one or more Steps. A JobInstance represents a given Job, parametrized with a set of typed properties called JobParameters. Each run of of aJobInstance is a JobExecution. Imagine a job reading entries from a data base and generating an xml representation of it and then doing some clean-up. We have a Jobcomposed of 2 steps: reading/writing and clean-up. If we parametrize this job by the date of the generated data then our Friday the 13th job is a JobInstance. Each time we run this instance (if a failure occurs for instance) is a JobExecution. This model gives a great flexibility regarding how jobs are launched and run. This naturally brings us to launching jobs with their job parameters, which is the responsibility of JobLauncher. Finally, various objects in the framework require a JobRepository to store runtime information related to the batch execution. In fact, Spring Batch domain model is much more elaborate but this will suffice for our purpose.
Well, it took more than 2 words and I feel compelled to make a joke about it, but I won't. So let's move to the next section.

Common Objects

For each job, we will use a separate xml context definition file. However there is a number of common objects that we will need recurrently. I will group them in an applicationContext.xml which will be imported from within job definitions. Let's go through these common objects:
JobLauncher
JobLaunchers are responsible for starting a Job with a given job parameters. The provided implementation, SimpleJobLauncher, relies on a TaskExecutor to launch the jobs. If no specific TaskExecutor is set then a SyncTaskExecutor is used.
JobRepository
We will use the SimpleJobRepository implementation which requires a set of execution Daos to store its information.
JobInstanceDao, JobExecutionDao, StepExecutionDao
These data access objects are used by SimpleJobRepository to store execution related information. Two sets of implementations are provided by Spring Batch: Map based (in-memory) and Jdbc based. In a real application the Jdbc variants are more suitable but we will use the simpler in-memory alternative in this example.
Here's our applicationContext.xml:
  1. <beans xmlns="http://www.springframework.org/schema/beans"  
  2.     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  
  3.     xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">  
  4.   
  5.   <bean id="jobLauncher" class="org.springframework.batch.core.launch.support.SimpleJobLauncher">  
  6.       <property name="jobRepository" ref="jobRepository"/>  
  7.   </bean>  
  8.       
  9.   <bean id="jobRepository" class="org.springframework.batch.core.repository.support.SimpleJobRepository">  
  10.       <constructor-arg>  
  11.           <bean class="org.springframework.batch.core.repository.dao.MapJobInstanceDao"/>  
  12.       </constructor-arg>  
  13.       <constructor-arg>  
  14.           <bean class="org.springframework.batch.core.repository.dao.MapJobExecutionDao" />  
  15.       </constructor-arg>  
  16.       <constructor-arg>  
  17.           <bean class="org.springframework.batch.core.repository.dao.MapStepExecutionDao"/>  
  18.       </constructor-arg>  
  19.   </bean>  
  20.   
  21. </beans>  

Hello World with Tasklets

A tasklet is an object containing any custom logic to be executed as a part of a job. Tasklets are built by implementing the Tasklet interface. Let's implement a simple tasklet that simply prints a message:
  1. public class PrintTasklet implements Tasklet{  
  2.   
  3.   private String message;  
  4.   
  5.   public void setMessage(String message) {  
  6.       this.message = message;  
  7.   }  
  8.       
  9.   public ExitStatus execute() throws Exception {  
  10.       System.out.print(message);  
  11.       return ExitStatus.FINISHED;  
  12.   }  
  13. }  
Notice that the execute method returns an ExitStatus to indicate the status of the execution of the tasklet.
We will define our first job now in a simpleJob.xml application context. We will use theSimpleJob implementation which executes all of its steps sequentailly. In order to plug a tasklet into a job, we need a TaskletStep. I also added an abstract bean definition for tasklet steps in order to simplify the configuration:
  1. <beans xmlns="http://www.springframework.org/schema/beans"  
  2.     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  
  3.     xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">  
  4.                                   
  5.   <import resource="applicationContext.xml"/>  
  6.       
  7.   <bean id="hello" class="helloworld.PrintTasklet">  
  8.       <property name="message" value="Hello"/>  
  9.   </bean>  
  10.       
  11.   <bean id="space" class="helloworld.PrintTasklet">  
  12.       <property name="message" value=" "/>  
  13.   </bean>  
  14.      
  15.   <bean id="world" class="helloworld.PrintTasklet">  
  16.       <property name="message" value="World!"/>  
  17.   </bean>  
  18.   
  19.   <bean id="taskletStep" abstract="true"  
  20.       class="org.springframework.batch.core.step.tasklet.TaskletStep">  
  21.       <property name="jobRepository" ref="jobRepository"/>  
  22.   </bean>  
  23.       
  24.   <bean id="simpleJob" class="org.springframework.batch.core.job.SimpleJob">  
  25.       <property name="name" value="simpleJob" />  
  26.       <property name="steps">  
  27.           <list>  
  28.               <bean parent="taskletStep">  
  29.                   <property name="tasklet" ref="hello"/>  
  30.               </bean>  
  31.               <bean parent="taskletStep">  
  32.                   <property name="tasklet" ref="space"/>  
  33.               </bean>  
  34.               <bean parent="taskletStep">;  
  35.                   <property name="tasklet" ref="world"/>  
  36.               </bean>  
  37.           </list>  
  38.       </property>  
  39.       <property name="jobRepository" ref="jobRepository"/>  
  40.   </bean>  
  41. </beans>  

Running the Job

Now we need something to kick-start the execution of our jobs. Spring Batch provides a convenient class to achieve that from the command line: CommandLineJobRunner. In its simplest form this class takes 2 arguments: the xml application context containing the job to launch and the bean id of that job. It naturally requires a JobLauncher to be configured in the application context. Here's how to launch the job with Maven. Of course, it can be run with the java command directly (you need to specify the class path then):

mvn exec:java -Dexec.mainClass=
org.springframework.batch.core.launch.support.CommandLineJobRunner 
-Dexec.args="simpleJob.xml simpleJob"

Hopefully, your efforts will be rewarded with a "Hello World!" printed on the console.
The code source can be downloaded here.

What's Next?

This is the first part of 3. In the next part we will improve on this example while the third part will be dedicated to item oriented steps and flat files readers and writers. Hope you find it useful.

No comments: