Spring Batch + Spring TaskScheduler example

In this tutorial, we will show you how to use Spring TaskScheduler to schedule a batch job to run every 5 seconds.

Tools and libraries used

  1. Maven 3
  2. Eclipse 4.2
  3. JDK 1.6
  4. Spring Core 3.2.2.RELEASE
  5. Spring Batch 2.2.0.RELEASE

1. Project Directory Structure

A standard Maven project.

spring-batch-taskscheduler

2. Spring TaskScheduler

Spring 3.0 introduces a TaskScheduler for scheduling tasks. It’s part of the Spring-Core, no need to declare an extra dependency.


  <task:scheduled-tasks>
	<task:scheduled ref="runScheduler" method="run" fixed-delay="5000" />
  </task:scheduled-tasks>
	
  <task:scheduled-tasks>
	<task:scheduled ref="runScheduler" method="run" cron="*/5 * * * * *" />
  </task:scheduled-tasks>

The TaskScheduler will schedule to run below bean.

RunScheduler.java

package com.mkyong;

import java.util.Date;

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;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

@Component
public class RunScheduler {

  @Autowired
  private JobLauncher jobLauncher;

  @Autowired
  private Job job;

  public void run() {

    try {

	String dateParam = new Date().toString();
	JobParameters param = 
	  new JobParametersBuilder().addString("date", dateParam).toJobParameters();
			
	System.out.println(dateParam);
			
	JobExecution execution = jobLauncher.run(job, param);
	System.out.println("Exit Status : " + execution.getStatus());

    } catch (Exception e) {
	e.printStackTrace();
    }

  }
}

P.S JobParamater need to be unique each time a batch job to run, for testing purpose, we just pass in a new Date() everything running the job.

3. Spring Batch Jobs

This job is just reading a csv file and display the value via a custom writer. Refer to the end of the file, we use task:scheduled-tasks to run this batch job every 5 seconds.

resources/spring/batch/jobs/job-report.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:batch="http://www.springframework.org/schema/batch"
	xmlns:context="http://www.springframework.org/schema/context"
	xmlns:task="http://www.springframework.org/schema/task" 
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://www.springframework.org/schema/batch
	http://www.springframework.org/schema/batch/spring-batch-2.2.xsd
	http://www.springframework.org/schema/beans 
	http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
	http://www.springframework.org/schema/context
	http://www.springframework.org/schema/context/spring-context-3.2.xsd
	http://www.springframework.org/schema/task
        http://www.springframework.org/schema/task/spring-task-3.2.xsd
	">

  <context:component-scan base-package="com.mkyong" />

  <!-- job context -->
  <bean id="jobRepository"
	class="org.springframework.batch.core.repository.support.MapJobRepositoryFactoryBean">
	<property name="transactionManager" ref="transactionManager" />
  </bean>

  <bean id="transactionManager"
	class="org.springframework.batch.support.transaction.ResourcelessTransactionManager" />

  <bean id="jobLauncher"
	class="org.springframework.batch.core.launch.support.SimpleJobLauncher">
	<property name="jobRepository" ref="jobRepository" />
  </bean>
  <!-- job context -->
	
  <bean id="report" class="com.mkyong.model.Report" scope="prototype" />

  <bean id="customWriter" class="com.mkyong.writers.CustomWriter" />

  <batch:job id="reportJob">
	<batch:step id="step1">
	  <batch:tasklet>
		<batch:chunk reader="cvsFileItemReader" writer="customWriter"
			commit-interval="10">
		</batch:chunk>
	  </batch:tasklet>
	</batch:step>
   </batch:job>

  <bean id="cvsFileItemReader" 
        class="org.springframework.batch.item.file.FlatFileItemReader">

	<!-- Read a csv file -->
	<property name="resource" value="classpath:cvs/input/report.csv" />

	<property name="lineMapper">
	  <bean class="org.springframework.batch.item.file.mapping.DefaultLineMapper">
		<property name="lineTokenizer">
		  <bean
			class="org.springframework.batch.item.file.transform.DelimitedLineTokenizer">
			<property name="names" value="id,impressions" />
		  </bean>
		</property>
		<property name="fieldSetMapper">
		  <bean
			class="org.springframework.batch.item.file.mapping.BeanWrapperFieldSetMapper">
			<property name="prototypeBeanName" value="report" />
		  </bean>
		</property>
	  </bean>
	</property>

  </bean>

  <bean id="runScheduler" class="com.mkyong.RunScheduler" />

  <!-- Run every 5 seconds -->
  <task:scheduled-tasks>
    <!-- 
	<task:scheduled ref="runScheduler" method="run" fixed-delay="5000" /> 
    -->
	<task:scheduled ref="runScheduler" method="run" cron="*/5 * * * * *" />
   </task:scheduled-tasks>

</beans>
report.csv

1,"139,237"
2,"500,657"
3,"342,100"
CustomWriter.java

package com.mkyong.writers;

import java.util.List;
import org.springframework.batch.item.ItemWriter;
import com.mkyong.model.Report;

public class CustomWriter implements ItemWriter<Report> {

  @Override
  public void write(List<? extends Report> items) throws Exception {

	System.out.println("writer..." + items.size());		
	for(Report item : items){
		System.out.println(item);
	}

  }

}

4. Run It

Loads the Spring application context, the scheduler will be run automatically.

App.java

package com.mkyong;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class App {
	
  public static void main(String[] args) {

	String springConfig = "spring/batch/jobs/job-report.xml";

	ApplicationContext context = new ClassPathXmlApplicationContext(springConfig);

  }
}

Output, it prints the csv content every 5 seconds.


......
Sun Jul 28 11:20:30 MYT 2013
Jul 28, 2013 11:20:30 AM org.springframework.batch.core.launch.support.SimpleJobLauncher$1 run
INFO: Job: [FlowJob: [name=reportJob]] launched with the following parameters: [{date=Sun Jul 28 11:20:30 MYT 2013}]
Jul 28, 2013 11:20:30 AM org.springframework.batch.core.job.SimpleStepHandler handleStep
INFO: Executing step: [step1]
writer...3
Report [id=1, Impressions=139,237]
Report [id=2, Impressions=500,657]
Report [id=3, Impressions=342,100]
Jul 28, 2013 11:20:30 AM org.springframework.batch.core.launch.support.SimpleJobLauncher$1 run
INFO: Job: [FlowJob: [name=reportJob]] completed with the following parameters: [{date=Sun Jul 28 11:20:30 MYT 2013}] and the following status: [COMPLETED]
Exit Status : COMPLETED

Sun Jul 28 11:20:35 MYT 2013
Jul 28, 2013 11:20:35 AM org.springframework.batch.core.launch.support.SimpleJobLauncher$1 run
INFO: Job: [FlowJob: [name=reportJob]] launched with the following parameters: [{date=Sun Jul 28 11:20:35 MYT 2013}]
Jul 28, 2013 11:20:35 AM org.springframework.batch.core.job.SimpleStepHandler handleStep
INFO: Executing step: [step1]
writer...3
Report [id=1, Impressions=139,237]
Report [id=2, Impressions=500,657]
Report [id=3, Impressions=342,100]
Exit Status : COMPLETED
Jul 28, 2013 11:20:35 AM org.springframework.batch.core.launch.support.SimpleJobLauncher$1 run
INFO: Job: [FlowJob: [name=reportJob]] completed with the following parameters: [{date=Sun Jul 28 11:20:35 MYT 2013}] and the following status: [COMPLETED]
......

Download Source Code

Download it – SpringBatch-TaskScheduler-Example.zip (18 kb)

References

  1. Spring – Schedululing a task.
  2. Wiki : Cron

About the Author

author image
mkyong
Founder of Mkyong.com, love Java and open source stuff. Follow him on Twitter. If you like my tutorials, consider make a donation to these charities.

Comments

avatar
16 Comment threads
1 Thread replies
0 Followers
 
Most reacted comment
Hottest comment thread
14 Comment authors
EnginPavanRameshcozuwiggin Recent comment authors
newest oldest most voted
Engin
Guest
Engin

Thoese getting : ASM ClassReader failed to parse class file.
–> You need to upgrade to Spring 4 in pom.xml if you want compile code to Java 8 :

4.0.6.RELEASE
3.0.2.RELEASE

Pavan
Guest
Pavan

I’m trying to run a batch job which has different batch steps and want to give cron job for each step.

Pavan
Guest
Pavan

Is there any way we can schedule the batch step?

Ramesh
Guest
Ramesh

Exact error while writing to DB
——————————————————
Oct 11, 2016 10:24:07 AM org.springframework.batch.core.launch.support.SimpleJobLauncher$1 run
INFO: Job: [FlowJob: [name=reportJob]] completed with the following parameters: [{}] and the following status: [COMPLETED]
Exit Status : COMPLETED
Done
java.lang.NullPointerExceptionTue Oct 11 10:24:10 SGT 2016

at com.mkyong.RunScheduler.run(RunScheduler.java:32)

Ramesh
Guest
Ramesh

Hi Thanks for the post.,

I am using this example for my scheduling

but i am facing error while writing to Db(using your previous example-SpringBatchExample)

goal: insted of writing to custom writer i want to write to Db

please suggest
———–
Done
Tue Oct 11 10:04:25 SGT 2016
java.lang.NullPointerException
at com.mkyong.RunScheduler.run(RunScheduler.java:32)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.springframework.scheduling.support.ScheduledMethodRunnable.run(ScheduledMethodRunnable.java:64)
at org.springframework.scheduling.support.DelegatingErrorHandlingRunnable.run(DelegatingErrorHandlingRunnable.java:53)
at org.springframework.scheduling.concurrent.ReschedulingRunnable.run(ReschedulingRunnable.java:81)
at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511)
at java.util.concurrent.FutureTask.run(FutureTask.java:266)
at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.access$201(ScheduledThreadPoolExecutor.java:180)
at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:293)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
at java.lang.Thread.run(Thread.java:745)
Tue Oct 11 10:04:30 SGT 2016
java.lang.NullPointerException
at com.mkyong.RunScheduler.run(RunScheduler.java:32)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.springframework.scheduling.support.ScheduledMethodRunnable.run(ScheduledMethodRunnable.java:64)
at org.springframework.scheduling.support.DelegatingErrorHandlingRunnable.run(DelegatingErrorHandlingRunnable.java:53)
at org.springframework.scheduling.concurrent.ReschedulingRunnable.run(ReschedulingRunnable.java:81)
at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511)
at java.util.concurrent.FutureTask.run(FutureTask.java:266)
at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.access$201(ScheduledThreadPoolExecutor.java:180)
at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:293)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
at java.lang.Thread.run(Thread.java:745)
Tue Oct 11 10:04:35 SGT 2016
java.lang.NullPointerException
at com.mkyong.RunScheduler.run(

cozu
Guest
cozu

Hello,

there any way to parameterize the cron from java ?

That is, to consult a database for the parameters and then assign it to cron cron… so that the cron is dynamic .

wiggin
Guest
wiggin

hello it’s possible that’s desirable to add getters and setters especially the first to Run Job class

by the way thanks a lot for such usefull tutorial i love this page.

coder
Guest
coder

Whenever I search for something on Java, this site always turns up in results. And unfortunately, most of articles here are outdated and uncooked. The example of spring batch here as well is so trivial and unsuitable for production use. It doesn’t even make use of spring annotation. Who creates XML now-a-days ?? I hope that Google downgrade this site and doesn’t show up mis-guiding links from it.

JN_Grx
Guest
JN_Grx

Hello,
Nice tuto, but with Spring 3 wouldn’t it be smarter to use Spring scheduler annotations ?

Leo
Guest
Leo

Here is the link for LeoTask – a lightweight parallel task running and results aggregation framework. https://github.com/mleoking/leotask

Leo
Guest
Leo

You can also use LeoTask – a lightweight parallel task running and results aggregation framework.To do the same job, it requires much less code and configuration. In addition, it enables applications to recovery from interruptions (e.g. Power Cut)

David Kingsbury
Guest
David Kingsbury

The POM included with the source doesn’t seem to create a complete JAR. If you’re getting class definition errors, try using the maven shade plugin to create the JAR. This is a link to the updated POM: http://pastebin.com/Q6B5sPgq

Amit Swain
Guest
Amit Swain

Hello I tried to run the executable jar it gives me error

D:amitIMPORTANTjavaSpringBatchExampletarget>java -jar spring-batch.jar
no main manifest attribute, in spring-batch.jar

Can you suggest a solution

Anonymous
Guest
Anonymous

Hi,
I have some doubt in spring batch scheduler. I need to read multiple files from a source folder. If a file copy is in progress during the batch job trigger, whther that partially copied file will be picked up by job? If so how to omit that… Ideally i need my job to pick only fully copied files from source folder. How do i achieve this? please help…

Nilesh Kamani
Guest
Nilesh Kamani

My job runs every 5 minutes and even though the job started at 12:00 pm does not finish by 12:05, I want another job to kick off at 12:05. Above configuration is not working for this scenario. Could you please tell me how I can setup like this ?

Daali Youssef
Guest
Daali Youssef

Can I use this to take an action every 24hours for example in a web app?

Guizmoo
Guest
Guizmoo