Spring-Batch Tutorial
Guide for Application Developers
Agenda
Hello world! job Simple job programming a Tasklet directly Common job weaving standard components Sample jobs
Hello World! - tasklet
public class HelloWorldTasklet implements Tasklet { public ExitStatus execute() throws Exception { [Link]("Hello world!"); return [Link]; }
Hello World! - tasklet
public class HelloWorldTasklet implements Tasklet { public ExitStatus execute() throws Exception { [Link]("Hello world!"); return [Link]; }
Hello World! - configuration
<bean id="jobConfiguration" parent="simpleJob"> <property name="name" value="helloWorldJob" /> <property name="steps"> <list> <bean id="step1" parent="simpleStep"> <constructor-arg> <bean class="...HelloWorldTasklet" /> </constructor-arg> </bean> </list> </property> </bean>
Hello World! - configuration
<bean id="jobConfiguration" parent="simpleJob"> <property name="name" value="helloWorldJob" /> <property name="steps"> <list> <bean id="step1" parent="simpleStep"> <constructor-arg> <bean class="...HelloWorldTasklet" /> </constructor-arg> </bean> </list> </property> </bean>
Simple job - tasklet
public class SimpleTasklet implements Tasklet { private InputSource inputSource; private OutputSource outputSource; public ExitStatus execute() throws Exception { Object data = [Link](); if (data != null) { [Link](data); return [Link]; } return [Link]; } public void setInputSource(InputSource inputSource) { [Link] = inputSource; } public void setOutputSource(OutputSource outputSource) { [Link] = outputSource; } }
Simple job - tasklet
public class SimpleTasklet implements Tasklet { private InputSource inputSource; private OutputSource outputSource; public ExitStatus execute() throws Exception { Object data = [Link](); if (data != null) { [Link](data); return [Link]; } return [Link]; } public void setInputSource(InputSource inputSource) { [Link] = inputSource; } public void setOutputSource(OutputSource outputSource) { [Link] = outputSource; } }
Simple job - tasklet
public class SimpleTasklet implements Tasklet { private InputSource inputSource; private OutputSource outputSource; public ExitStatus execute() throws Exception { Object data = [Link](); if (data != null) { [Link](data); return [Link]; } return [Link]; } public void setInputSource(InputSource inputSource) { [Link] = inputSource; } public void setOutputSource(OutputSource outputSource) { [Link] = outputSource; } }
Simple job - configuration
<bean id="jobConfiguration" parent="simpleJob"> <property name="name" value="simpleTaskletJob" /> <property name="steps"> <list> <bean id="step1" parent="simpleStep"> <constructor-arg> <bean class="...SimpleTasklet"> <property name="inputSource" ref="inputSource" /> <property name="outputSource" ref="outputSource" /> </bean> </constructor-arg> </bean> </list> </property> </bean>
Simple job input source
<bean id=inputSource" class="...SqlCursorInputSource scope="step" > <aop:scoped-proxy /> <property name="dataSource" ref="dataSource" /> <property name="sql" value="SELECT id, quantity, price, customer from TRADE" /> <property name="mapper"> <bean class="...TradeRowMapper" /> </property> </bean>
Simple job input source
<bean id=inputSource" class="...SqlCursorInputSource scope="step" > <aop:scoped-proxy /> <constructor-arg> <ref bean="dataSource" /> </constructor-arg> <property name="sql" value="SELECT id, quantity, price, customer from TRADE" /> <property name="mapper"> <bean class="...TradeRowMapper" /> </property> </bean>
Simple job output source
<bean id="outputSource" class="...FlatFileOutputSource scope="step" > <aop:scoped-proxy /> <property name="resource" value="file:[Link]" /> </bean>
Common job - configuration
<bean id="jobConfiguration" parent="simpleJob"> <property name="name" value="commonJob" /> <property name="steps"> <bean id="step1" parent="simpleStep"> <constructor-arg> <bean class="...[Link]"> <property name="itemProvider"> <bean class="...[Link]"> <property name="source" ref="sqlInputSource" /> </bean> </property> <property name="itemProcessor"> <bean class="...[Link]"> <property name="source" ref="xmlOutputSource" /> </bean> </property> </bean> </constructor-arg> </bean> </property> </bean>
Common job tasklet
<bean class="...[Link]"> <property name="itemProvider"> <bean class="...[Link]"> <property name="source" ref="sqlInputSource" /> </bean> </property> <property name="itemProcessor"> <bean class="...[Link]"> <property name="source" ref="xmlOutputSource" /> </bean> </property> </bean>
Common job tasklet
<bean class="...[Link]"> <property name="itemProvider"> <bean class="...[Link]"> <property name="source" ref="sqlInputSource" /> </bean> </property> <property name="itemProcessor"> <bean class="...[Link]"> <property name="source" ref="xmlOutputSource" /> </bean> </property>
</bean>
Common job tasklet
<bean class="...[Link]"> <property name="itemProvider"> <bean class="...[Link]"> <property name="source" ref="sqlInputSource" /> </bean> </property> <property name="itemProcessor"> <bean class="...[Link]"> <property name="source" ref="xmlOutputSource" /> </bean> </property>
</bean>
Samples overview
Samples project contains simple batch jobs illustrating various capabilities of the Spring-Batch framework See the folder src/main/resources/jobs for job configuration files See src/test/java, package [Link] for tests which launch the jobs and check the expected results
[Link]
Straightforwardly implemented Tasklet, similar to the Simple Job example All-in-one solution to help understand tasklets execution logic Standard solutions are more modular, which makes them more flexible and reusable, but also less straightforward to understand
[Link]
Clean separation of reading input and processing data (standard from now on) Typical scenario of importing data from a fixed-length file to database Custom DAO used for output
[Link]
Handling of complex file format, both reading input and writing output Single record spans multiple lines and has nested records Custom ItemProvider and ItemProcessor implementations handling non-standard file format
[Link]
shows a reasonably complex scenario, that would resemble the real-life usage of the framework 3 steps:
trade records are imported from file to database customer account balance is adjusted report about customers is exported to a file
[Link]
Parallel writing to multiple outputs Example usage of composite ItemProcessor with an injected list of ItemProcessors
[Link]
Simulates restart scenario, where the job crashes on first run and succeeds after being restarted Uses hacked tasklet that throws exception after reading a given number of records