Tareq has posted 1 posts at DZone. View Full User Profile

Spring Batch - Hello World

05.23.2008
| 191568 views |
  • submit to reddit

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 a JobInstance 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 Job composed 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:

<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans-2.5.xsd">

  <bean id="jobLauncher" class="org.springframework.batch.core.launch.support.SimpleJobLauncher">
      <property name="jobRepository" ref="jobRepository"/>
  </bean>
    
  <bean id="jobRepository" class="org.springframework.batch.core.repository.support.SimpleJobRepository">
      <constructor-arg>
          <bean class="org.springframework.batch.core.repository.dao.MapJobInstanceDao"/>
      </constructor-arg>
      <constructor-arg>
          <bean class="org.springframework.batch.core.repository.dao.MapJobExecutionDao" />
      </constructor-arg>
      <constructor-arg>
          <bean class="org.springframework.batch.core.repository.dao.MapStepExecutionDao"/>
      </constructor-arg>
  </bean>

</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:

public class PrintTasklet implements Tasklet{

  private String message;

  public void setMessage(String message) {
      this.message = message;
  }
    
  public ExitStatus execute() throws Exception {
      System.out.print(message);
      return ExitStatus.FINISHED;
  }
}

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 the SimpleJob 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:

<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans-2.5.xsd">
                                
  <import resource="applicationContext.xml"/>
    
  <bean id="hello" class="helloworld.PrintTasklet">
      <property name="message" value="Hello"/>
  </bean>
    
  <bean id="space" class="helloworld.PrintTasklet">
      <property name="message" value=" "/>
  </bean>
   
  <bean id="world" class="helloworld.PrintTasklet">
      <property name="message" value="World!"/>
  </bean>

  <bean id="taskletStep" abstract="true"
      class="org.springframework.batch.core.step.tasklet.TaskletStep">
      <property name="jobRepository" ref="jobRepository"/>
  </bean>
    
  <bean id="simpleJob" class="org.springframework.batch.core.job.SimpleJob">
      <property name="name" value="simpleJob" />
      <property name="steps">
          <list>
              <bean parent="taskletStep">
                  <property name="tasklet" ref="hello"/>
              </bean>
              <bean parent="taskletStep">
                  <property name="tasklet" ref="space"/>
              </bean>
              <bean parent="taskletStep">;
                  <property name="tasklet" ref="world"/>
              </bean>
          </list>
      </property>
      <property name="jobRepository" ref="jobRepository"/>
  </bean>
</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.

References
Published at DZone with permission of its author, Tareq Abedrabbo. (source)

(Note: Opinions expressed in this article and its replies are the opinions of their respective authors and not those of DZone, Inc.)

Comments

Alexander Shvets replied on Fri, 2008/05/23 - 9:00am

Nice introduction. Why do you have runtime scope in your pom file? I had to comment them in order to run the example.

Do you know if there is a way to "substitute" job execution with another implementation, like Quartz job scheduling system?

 

Tareq Abedrabbo replied on Fri, 2008/05/23 - 2:26pm

Thanks! The runtime scopes are because these dependencies are not required to build the application but only to run it. I think that the Maven exec plugins ignores them (I had this problem in one environment). Anyhow, I modified the pom. Thanks for pointing out this. As for the scheduling part of the question, Spring Batch does not schedule jobs. However, you can use Quartz or any other scheduler to schedule Spring Batch jobs.

Joergen Larsen replied on Sat, 2008/05/24 - 3:54am

 

Thanks Tareq Abed, greate introduction - looking forward to next part. 

Tareq Abedrabbo replied on Sat, 2008/05/24 - 10:38am in response to: Joergen Larsen

Thanks Joergen. It's on its way!

Paul Hill replied on Wed, 2008/06/04 - 11:33am

Typo on line 3 of applicationContext.xml and simpleJob.xml

xsi:schemaLocation="http://.../beanshttp://www..../spring-beans-2.5.xsd">

needs a space after bean and before http:

 

Typo on line 34 simpleJob.xml

<bean parent="taskletStep">;

Drop the semicolon

 

Typo in helloworld.PrintTasklet

since the job.xml file refers to helloworld.PrintTasklet the java file ought to put it in the right package.

add the line

package helloworld;

to PrintTasklet.java

-Paul

Simni Mama replied on Wed, 2009/04/08 - 2:45am

I have been trying to run this command on Command Line:
mvn exec:java -Dexec.mainClass=org.springframework.batch.core.launch.support.CommandLineJobRunner -Dexec.args="simpleJob.xml simpleJob"

 

but get the following error:

[INFO] Scanning for projects...
[INFO] Searching repository for plugin with prefix: 'exec'.
[INFO] org.apache.maven.plugins: checking for updates from central
[WARNING] repository metadata for: 'org.apache.maven.plugins' could not be retri
eved from repository: central due to an error: Error transferring file
[INFO] Repository 'central' will be blacklisted
[INFO] ------------------------------------------------------------------------
[ERROR] BUILD ERROR
[INFO] ------------------------------------------------------------------------
[INFO] The plugin 'org.apache.maven.plugins:maven-exec-plugin' does not exist or
 no valid version could be found
[INFO] ------------------------------------------------------------------------
[INFO] For more information, run Maven with the -e switch
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 1 second
[INFO] Finished at: Wed Apr 08 09:23:27 GMT+02:00 2009
[INFO] Final Memory: 1M/2M
[INFO] ------------------------------------------------------------------------

 

Please help as soon as possible.

Jeremy Leipzig replied on Wed, 2009/04/08 - 4:08pm

I couldn't see the hello world unless I redirected the output to a file

maven is very strange

victor joshua replied on Wed, 2009/10/21 - 11:51pm

hi, tried the followin cmd.. mvn exec:java -Dexec.mainClass=org.springframework.batch.core.launch.support.CommandLineJobRunner -Dexec.args="simpleJob.xml simpleJob" but i still get the followin msg:
[INFO] Scanning for projects...
[INFO] Searching repository for plugin with prefix: 'exec'.
[INFO] org.apache.maven.plugins: checking for updates from central
[WARNING] repository metadata for: 'org.apache.maven.plugins' could not be retrieved from repository: central due to an error
: Error transferring file
[INFO] Repository 'central' will be blacklisted
[INFO] ------------------------------------------------------------------------
[ERROR] BUILD ERROR
[INFO] ------------------------------------------------------------------------
[INFO] The plugin 'org.apache.maven.plugins:maven-exec-plugin' does not exist or no valid version could be found
[INFO] ------------------------------------------------------------------------
[INFO] For more information, run Maven with the -e switch
[INFO] ------------------------------------------------------------------------
[INFO] Total time: < 1 second
[INFO] Finished at: Wed Oct 21 19:27:04 IST 2009
[INFO] Final Memory: 1M/2M
[INFO] ------------------------------------------------------------------------

PLEASE HELP.
THANKS IN ADVANCE.

Juan Uys replied on Mon, 2010/02/08 - 10:12am

"The plugin 'org.apache.maven.plugins:maven-exec-plugin' does not exist or no valid version could be found" Try running Maven with "-U" so that it downloads the exec plugin.

Md Khan replied on Fri, 2010/04/23 - 5:13am

Can anyone plz suggest me the best link or book for Spring batch and Spring batch admin??? which contains the instruction that how to run the spring batch program step by step.. Thanks, Tanweer Khan

Deepak Mohanakr... replied on Sun, 2011/07/03 - 11:30pm

Dear Tareq,

 I am good at Spring framework. I just started exploring Spring Batch recently. I looked at your very useful and simple HelloWorld example. Thanks a ton for it. Could you please let me know how to achieve parallel processing in Spring Batch. I mean If I want to run the above three simple tasklets 10000 times parallaly in 20 threads. How to achieve it. I keep exploring Spring batch. But if you could answer could accelerate me in this regard.

Many Thanks,

Deepak

James Walker replied on Wed, 2012/06/20 - 7:30am

I have been thinking about the secret of life, but a secret is still a secret, i cannot figure it out in the end monterjet

Lucifer Williams replied on Fri, 2012/11/16 - 1:37pm

If we parametrize this job by the date of the generated vinyl storage rack 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.

Remya Nambiar replied on Tue, 2013/06/25 - 12:20pm

 I tried executing this example, both on the command prompt and through eclipse passing the parameters. But there are no errors or no output displayed. What may be wrong?

this is what i get on the console.


log4j:WARN No appenders could be found for logger (org.springframework.context.support.ClassPathXmlApplicationContext).
log4j:WARN Please initialize the log4j system properly.
log4j:WARN See http://logging.apache.org/log4j/1.2/faq.html#noconfig for more info.

Noel Padzinza replied on Wed, 2013/12/04 - 8:18am

Thanks for the tutorials Jareq. Very clear and easy to follow. Just wrote my first Spring Batch program. Much appreciated!! Noel - web design Melbourne 

Muzzammil Ahmed replied on Sat, 2013/12/14 - 1:11am

 Hi,

Could anyone help me out on this, when executing the above sample batch program.

I am getting the below exception on loading spring definitions by using spring batch 2.1.7 version and spring release is 3.0.6 version. Also the constructor arguments for "org.springframework.batch.core.repository.support.SimpleJobRepository" is 4 as  MapJobInstanceDao, MapJobExecutionDao, MapStepExecutionDao, MapExecutionContextDao.

Console Error :

2013-12-14 11:28:52,521 INFO [org.springframework.context.support.ClassPathXmlApplicationContext] - <Refreshing org.springframework.context.support.ClassPathXmlApplicationContext@5fb8424e: startup date [Sat Dec 14 11:28:52 IST 2013]; root of context hierarchy>
2013-12-14 11:28:52,823 INFO [org.springframework.beans.factory.xml.XmlBeanDefinitionReader] - <Loading XML bean definitions from class path resource [simpleJob.xml]>
2013-12-14 11:28:53,276 INFO [org.springframework.beans.factory.xml.XmlBeanDefinitionReader] - <Loading XML bean definitions from class path resource [applicationContext.xml]>
2013-12-14 11:28:53,548 INFO [org.springframework.beans.factory.support.DefaultListableBeanFactory] - <Pre-instantiating singletons in org.springframework.beans.factory.support.DefaultListableBeanFactory@35c283b5: defining beans [transactionManager,jobRepository,jobLauncher,hello,space,world,taskletStep,simpleJob]; root of factory hierarchy>
2013-12-14 11:28:54,078 INFO [org.springframework.batch.core.launch.support.SimpleJobLauncher] - <No TaskExecutor has been set, defaulting to synchronous executor.>
2013-12-14 11:28:54,331 INFO [org.springframework.beans.factory.support.DefaultListableBeanFactory] - <Destroying singletons in org.springframework.beans.factory.support.DefaultListableBeanFactory@35c283b5: defining beans [transactionManager,jobRepository,jobLauncher,hello,space,world,taskletStep,simpleJob]; root of factory hierarchy>
Exception in thread "main" org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'simpleJob' defined in class path resource [simpleJob.xml]: Invocation of init method failed; nested exception is java.lang.IllegalArgumentException: JobRepository must be set
   at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1420)
   at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:519)
   at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:456)
   at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:293)
   at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:222)
   at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:290)
   at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:192)
   at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:585)
   at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:895)
   at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:425)
   at org.springframework.context.support.ClassPathXmlApplicationContext.<init>(ClassPathXmlApplicationContext.java:139)
   at org.springframework.context.support.ClassPathXmlApplicationContext.<init>(ClassPathXmlApplicationContext.java:93)
   at com.simple.spring.SimpleJobTest.main(SimpleJobTest.java:25)
Caused by: java.lang.IllegalArgumentException: JobRepository must be set
   at org.springframework.util.Assert.notNull(Assert.java:112)
   at org.springframework.batch.core.job.AbstractJob.afterPropertiesSet(AbstractJob.java:109)
   at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1477)
   at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1417)
   ... 12 more

Comment viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.