BATCH-1131: Updated docs to show the new way of configuring transaction attributes.
This commit is contained in:
@@ -4,7 +4,7 @@
|
||||
<chapter id="configureStep">
|
||||
<title>Configuring a Step</title>
|
||||
|
||||
<para>As discussed in <xref linkend="domain"/>, a
|
||||
<para>As discussed in <xref linkend="domain" />, a
|
||||
<classname>Step</classname> is a domain object that encapsulates an
|
||||
independent, sequential phase of a batch job and contains all of the
|
||||
information necessary to define and control the actual batch processing.
|
||||
@@ -56,16 +56,16 @@
|
||||
<para>Below is a code representation of the same concepts shown
|
||||
above:</para>
|
||||
|
||||
<programlisting><![CDATA[
|
||||
<programlisting>
|
||||
List items = new Arraylist();
|
||||
for(int i = 0; i < commitInterval; i++){
|
||||
for(int i = 0; i < commitInterval; i++){
|
||||
Object item = itemReader.read()
|
||||
Object processedItem = itemProcessor.process(item);
|
||||
items.add(processedItem);
|
||||
}
|
||||
itemWriter.write(items);
|
||||
|
||||
]]></programlisting>
|
||||
</programlisting>
|
||||
|
||||
<section>
|
||||
<title>Configuring a Step</title>
|
||||
@@ -75,14 +75,14 @@
|
||||
potentially contain many collaborators. In order to ease configuration,
|
||||
the Spring Batch namespace can be used:</para>
|
||||
|
||||
<programlisting><![CDATA[
|
||||
<job id="sampleJob">
|
||||
<step id="step1" job-repository="jobRepository" transaction-manager="transactionManager">
|
||||
<tasklet reader="itemReader" writer="itemWriter" commit-interval="10"/>
|
||||
</step>
|
||||
</job>
|
||||
<programlisting>
|
||||
<job id="sampleJob">
|
||||
<step id="step1" job-repository="jobRepository" transaction-manager="transactionManager">
|
||||
<tasklet reader="itemReader" writer="itemWriter" commit-interval="10"/>
|
||||
</step>
|
||||
</job>
|
||||
|
||||
]]></programlisting>
|
||||
</programlisting>
|
||||
|
||||
<para>The configuration above represents the only required dependencies
|
||||
to create a item-oriented step:<itemizedlist>
|
||||
@@ -133,16 +133,16 @@
|
||||
reference it from multiple jobs. This can be achieved with the 'ref'
|
||||
attribute:</para>
|
||||
|
||||
<programlisting><![CDATA[
|
||||
<job id="sampleJob">
|
||||
<step id="step1" ]]><emphasis role="bold">ref="standaloneStep"</emphasis><![CDATA[ />
|
||||
</job>
|
||||
<programlisting>
|
||||
<job id="sampleJob">
|
||||
<step id="step1" <emphasis role="bold">ref="standaloneStep"</emphasis> />
|
||||
</job>
|
||||
|
||||
<step id="standaloneStep" job-repository="jobRepository" transaction-manager="transactionManager">
|
||||
<tasklet reader="itemReader" writer="itemWriter" commit-interval="10"/>
|
||||
</step>
|
||||
<step id="standaloneStep" job-repository="jobRepository" transaction-manager="transactionManager">
|
||||
<tasklet reader="itemReader" writer="itemWriter" commit-interval="10"/>
|
||||
</step>
|
||||
|
||||
]]></programlisting>
|
||||
</programlisting>
|
||||
|
||||
<para>It should be noted that the id attribute is still required on the
|
||||
step within the job element. This is for two reasons:</para>
|
||||
@@ -177,15 +177,15 @@
|
||||
number of items that are processed within a commit can be
|
||||
configured.</para>
|
||||
|
||||
<programlisting><![CDATA[
|
||||
<job id="sampleJob">
|
||||
<step id="step1" job-repository="jobRepository" transaction-manager="transactionManager">
|
||||
<tasklet reader="itemReader" writer="itemWriter" ]]><emphasis
|
||||
role="bold">commit-interval="10"</emphasis><![CDATA[/>
|
||||
</step>
|
||||
</job>
|
||||
<programlisting>
|
||||
<job id="sampleJob">
|
||||
<step id="step1" job-repository="jobRepository" transaction-manager="transactionManager">
|
||||
<tasklet reader="itemReader" writer="itemWriter" <emphasis
|
||||
role="bold">commit-interval="10"</emphasis>/>
|
||||
</step>
|
||||
</job>
|
||||
|
||||
]]></programlisting>
|
||||
</programlisting>
|
||||
|
||||
<para>In the example above, 10 items will be processed within each
|
||||
transaction. At the beginning of processing a transaction is begun, and
|
||||
@@ -217,13 +217,13 @@
|
||||
as a <classname>Step</classname> that can be run infinitely. Below is
|
||||
an example start limit configuration:</para>
|
||||
|
||||
<programlisting><![CDATA[
|
||||
<step id="step1">
|
||||
<tasklet reader="itemReader" writer="itemWriter" commit-interval="10" ]]><emphasis
|
||||
role="bold">start-limit="1"</emphasis><![CDATA[/>
|
||||
</step>
|
||||
<programlisting>
|
||||
<step id="step1">
|
||||
<tasklet reader="itemReader" writer="itemWriter" commit-interval="10" <emphasis
|
||||
role="bold">start-limit="1"</emphasis>/>
|
||||
</step>
|
||||
|
||||
]]></programlisting>
|
||||
</programlisting>
|
||||
|
||||
<para>The simple step above can be run only once. Attempting to run it
|
||||
again will cause an exception to be thrown. It should be noted that
|
||||
@@ -243,35 +243,35 @@
|
||||
successfully, will be skipped. Setting allow-start-if-complete to
|
||||
"true" overrides this so that the step will always run:</para>
|
||||
|
||||
<programlisting><![CDATA[
|
||||
<step id="step1">
|
||||
<tasklet reader="itemReader" writer="itemWriter" commit-interval="10"
|
||||
]]><emphasis role="bold">allow-start-if-complete="true"</emphasis><![CDATA[/>
|
||||
</step>
|
||||
<programlisting>
|
||||
<step id="step1">
|
||||
<tasklet reader="itemReader" writer="itemWriter" commit-interval="10"
|
||||
<emphasis role="bold">allow-start-if-complete="true"</emphasis>/>
|
||||
</step>
|
||||
|
||||
]]></programlisting>
|
||||
</programlisting>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<title>Step restart configuration example</title>
|
||||
|
||||
<programlisting><![CDATA[
|
||||
<job id="footballJob" restartable="true">
|
||||
<step id="playerload" next="gameLoad">
|
||||
<tasklet reader="playerFileItemReader" writer="playerWriter"
|
||||
commit-interval="10" />
|
||||
</step>
|
||||
<step id="gameLoad" next="playerSummarization">
|
||||
<tasklet reader="gameFileItemReader" writer="gameWriter"
|
||||
commit-interval="10" allow-start-if-complete="true"/>
|
||||
</step>
|
||||
<step id="playerSummarization">
|
||||
<tasklet reader="playerSummarizationSource" writer="summaryWriter"
|
||||
commit-interval="10" start-limit="3"/>
|
||||
</step>
|
||||
</job>
|
||||
<programlisting>
|
||||
<job id="footballJob" restartable="true">
|
||||
<step id="playerload" next="gameLoad">
|
||||
<tasklet reader="playerFileItemReader" writer="playerWriter"
|
||||
commit-interval="10" />
|
||||
</step>
|
||||
<step id="gameLoad" next="playerSummarization">
|
||||
<tasklet reader="gameFileItemReader" writer="gameWriter"
|
||||
commit-interval="10" allow-start-if-complete="true"/>
|
||||
</step>
|
||||
<step id="playerSummarization">
|
||||
<tasklet reader="playerSummarizationSource" writer="summaryWriter"
|
||||
commit-interval="10" start-limit="3"/>
|
||||
</step>
|
||||
</job>
|
||||
|
||||
]]></programlisting>
|
||||
</programlisting>
|
||||
|
||||
<para>The above example configuration is for a job that loads in
|
||||
information about football games and summarizes them. It contains
|
||||
@@ -384,17 +384,17 @@
|
||||
loaded because it was formatted incorrectly or was missing necessary
|
||||
information, then there probably won't be issues. Usually these bad
|
||||
records are logged as well, which will be covered later when discussing
|
||||
listeners.<programlisting><![CDATA[
|
||||
<step id="step1">
|
||||
<tasklet reader="flatFileItemReader" writer="itemWriter" commit-interval="10" ]]><emphasis
|
||||
role="bold">skip-limit="10"</emphasis><![CDATA[>
|
||||
]]><emphasis role="bold"><skippable-exception-classes>
|
||||
listeners.<programlisting>
|
||||
<step id="step1">
|
||||
<tasklet reader="flatFileItemReader" writer="itemWriter" commit-interval="10" <emphasis
|
||||
role="bold">skip-limit="10"</emphasis>>
|
||||
<emphasis role="bold"><skippable-exception-classes>
|
||||
org.springframework.batch.item.file.FlatFileParseException
|
||||
</skippable-exception-classes></emphasis><![CDATA[
|
||||
</tasklet>
|
||||
</step>
|
||||
</skippable-exception-classes></emphasis>
|
||||
</tasklet>
|
||||
</step>
|
||||
|
||||
]]></programlisting></para>
|
||||
</programlisting></para>
|
||||
|
||||
<para>In this example, a <classname>FlatFileItemReader</classname> is
|
||||
used, and if at any point a
|
||||
@@ -407,25 +407,26 @@
|
||||
|
||||
<section>
|
||||
<title>Configuring Fatal Exceptions</title>
|
||||
|
||||
<para>One problem with the example above is that any other exception
|
||||
besides a <classname>FlatFileParseException</classname> will cause the
|
||||
<classname>Job</classname> to fail. In certain scenarios this may be the
|
||||
correct behavior. However, in other scenarios it may be easier to
|
||||
identify which exceptions should cause failure and skip everything
|
||||
else:<programlisting><![CDATA[
|
||||
<step id="step1">
|
||||
<tasklet reader="flatFileItemReader" writer="itemWriter" commit-interval="10" ]]><emphasis
|
||||
role="bold">skip-limit="10"</emphasis><![CDATA[>
|
||||
]]><emphasis role="bold"> <skippable-exception-classes>
|
||||
else:<programlisting>
|
||||
<step id="step1">
|
||||
<tasklet reader="flatFileItemReader" writer="itemWriter" commit-interval="10" <emphasis
|
||||
role="bold">skip-limit="10"</emphasis>>
|
||||
<emphasis role="bold"> <skippable-exception-classes>
|
||||
java.lang.Exception
|
||||
</skippable-exception-classes>
|
||||
<fatal-exception-classes>
|
||||
java.io.FileNotFoundException
|
||||
</fatal-exception-classes>
|
||||
</emphasis><![CDATA[ </tasklet>
|
||||
</step>
|
||||
</emphasis> </tasklet>
|
||||
</step>
|
||||
|
||||
]]></programlisting></para>
|
||||
</programlisting></para>
|
||||
|
||||
<para>By setting the skippable exceptions to
|
||||
<classname>java.lang.Exception</classname>, any exception that is thrown
|
||||
@@ -447,17 +448,17 @@
|
||||
process holds a lock on, waiting and trying again might result in
|
||||
success. In this case, retry should be configured:</para>
|
||||
|
||||
<programlisting><![CDATA[
|
||||
<step id="step1">
|
||||
<tasklet reader="itemReader" writer="itemWriter" commit-interval="2" ]]><emphasis
|
||||
role="bold">retry-limit="3"</emphasis><![CDATA[>
|
||||
]]><emphasis role="bold"><retryable-exception-classes>
|
||||
<programlisting>
|
||||
<step id="step1">
|
||||
<tasklet reader="itemReader" writer="itemWriter" commit-interval="2" <emphasis
|
||||
role="bold">retry-limit="3"</emphasis>>
|
||||
<emphasis role="bold"><retryable-exception-classes>
|
||||
org.springframework.dao.DeadlockLoserDataAccessException
|
||||
</retryable-exception-classes></emphasis><![CDATA[
|
||||
</tasklet>
|
||||
</step>
|
||||
</retryable-exception-classes></emphasis>
|
||||
</tasklet>
|
||||
</step>
|
||||
|
||||
]]></programlisting>
|
||||
</programlisting>
|
||||
|
||||
<para>The <classname>Step</classname> allows a limit for the number of
|
||||
times an individual item can be retried, and a list of exceptions that
|
||||
@@ -477,23 +478,24 @@
|
||||
<classname>ItemWriter</classname> should not cause a rollback because no
|
||||
action has taken place to invalidate the transaction. For this reason,
|
||||
the <classname>Step</classname> can be configured with a list of
|
||||
exceptions that should not cause rollback. The transaction-attribute
|
||||
attribute is a comma-separated list. Prefixing a class name with the "+"
|
||||
symbol will indicate that that exception should not cause
|
||||
rollback.</para>
|
||||
exceptions that should not cause rollback. The transaction-attributes
|
||||
element is a list of transaction attributes, separated by commas or
|
||||
newlines. Prefixing a class name with the "+" symbol will indicate that
|
||||
that exception should not cause rollback.</para>
|
||||
|
||||
<programlisting><![CDATA[
|
||||
<step id="step1">
|
||||
<tasklet reader="itemReader" writer="itemWriter" commit-interval="2" skip-limit="1"
|
||||
]]><emphasis role="bold">transaction-attribute="+org.springframework.batch.item.validator.ValidationException"</emphasis><![CDATA[>
|
||||
</tasklet>
|
||||
</step>
|
||||
<programlisting>
|
||||
<step id="step1">
|
||||
<tasklet reader="itemReader" writer="itemWriter" commit-interval="2" skip-limit="1"/>
|
||||
<transaction-attributes>
|
||||
+org.springframework.batch.item.validator.ValidationException
|
||||
</transaction-attributes>
|
||||
</step>
|
||||
|
||||
]]></programlisting>
|
||||
</programlisting>
|
||||
|
||||
<para>Transaction attributes can be used to control multiple other
|
||||
settings such as isolation and propagation behavior. More information on
|
||||
setting transaction attributes can be found in the spring core
|
||||
<para>Transaction attributes can also be used to control other settings
|
||||
such as isolation and propagation behavior. More information on setting
|
||||
transaction attributes can be found in the spring core
|
||||
documentation.</para>
|
||||
|
||||
<section id="transactionalReaders">
|
||||
@@ -509,14 +511,14 @@
|
||||
this reason, the step can be configured to not buffer the
|
||||
items:</para>
|
||||
|
||||
<programlisting><![CDATA[
|
||||
<step id="step1">
|
||||
<tasklet reader="itemReader" writer="itemWriter" commit-interval="2" skip-limit="1"
|
||||
]]><emphasis role="bold">is-reader-transactional-queue="true"</emphasis><![CDATA[>
|
||||
</tasklet>
|
||||
</step>
|
||||
<programlisting>
|
||||
<step id="step1">
|
||||
<tasklet reader="itemReader" writer="itemWriter" commit-interval="2" skip-limit="1"
|
||||
<emphasis role="bold">is-reader-transactional-queue="true"</emphasis>>
|
||||
</tasklet>
|
||||
</step>
|
||||
|
||||
]]></programlisting>
|
||||
</programlisting>
|
||||
</section>
|
||||
</section>
|
||||
|
||||
@@ -541,27 +543,27 @@
|
||||
can be registered on the <classname>Step</classname> through the
|
||||
'streams' element, as illustrated below:</para>
|
||||
|
||||
<programlisting><![CDATA[
|
||||
<step id="step1">
|
||||
<tasklet reader="itemReader" writer="compositeWriter" commit-interval="2">
|
||||
]]><emphasis role="bold"><streams>
|
||||
<programlisting>
|
||||
<step id="step1">
|
||||
<tasklet reader="itemReader" writer="compositeWriter" commit-interval="2">
|
||||
<emphasis role="bold"><streams>
|
||||
<stream ref="fileItemWriter1"/>
|
||||
<stream ref="fileItemWriter2"/>
|
||||
</streams></emphasis><![CDATA[
|
||||
</tasklet>
|
||||
</step>
|
||||
</streams></emphasis>
|
||||
</tasklet>
|
||||
</step>
|
||||
|
||||
<beans:bean id="compositeWriter"
|
||||
class="org.springframework.batch.item.support.CompositeItemWriter">
|
||||
<beans:property name="delegates">
|
||||
<beans:list>
|
||||
<beans:ref bean="fileItemWriter1" />
|
||||
<beans:ref bean="fileItemWriter2" />
|
||||
</beans:list>
|
||||
</beans:property>
|
||||
</beans:bean>
|
||||
<beans:bean id="compositeWriter"
|
||||
class="org.springframework.batch.item.support.CompositeItemWriter">
|
||||
<beans:property name="delegates">
|
||||
<beans:list>
|
||||
<beans:ref bean="fileItemWriter1" />
|
||||
<beans:ref bean="fileItemWriter2" />
|
||||
</beans:list>
|
||||
</beans:property>
|
||||
</beans:bean>
|
||||
|
||||
]]></programlisting>
|
||||
</programlisting>
|
||||
|
||||
<para>In the example above, the
|
||||
<classname>CompositeItemWriter</classname> is not an
|
||||
@@ -591,15 +593,15 @@
|
||||
interface (or an extension thereof) can be applied to a step via the
|
||||
listeners element:</para>
|
||||
|
||||
<programlisting><![CDATA[
|
||||
<step id="step1">
|
||||
<tasklet reader="reader" writer="writer" commit-interval="10"/>
|
||||
<listeners>
|
||||
<listener ref="stepListener"/>
|
||||
</listeners>
|
||||
</step>
|
||||
<programlisting>
|
||||
<step id="step1">
|
||||
<tasklet reader="reader" writer="writer" commit-interval="10"/>
|
||||
<listeners>
|
||||
<listener ref="stepListener"/>
|
||||
</listeners>
|
||||
</step>
|
||||
|
||||
]]></programlisting>
|
||||
</programlisting>
|
||||
|
||||
<para>In addition to the <classname>StepListener</classname> interfaces,
|
||||
annotations are provided to address the same concerns.</para>
|
||||
@@ -612,7 +614,7 @@
|
||||
for notification before a <classname>Step</classname> is started and
|
||||
after it has ends, whether it ended normally or failed:</para>
|
||||
|
||||
<programlisting><![CDATA[
|
||||
<programlisting>
|
||||
public interface StepExecutionListener extends StepListener {
|
||||
|
||||
void beforeStep(StepExecution stepExecution);
|
||||
@@ -620,7 +622,7 @@
|
||||
ExitStatus afterStep(StepExecution stepExecution);
|
||||
}
|
||||
|
||||
]]></programlisting>
|
||||
</programlisting>
|
||||
|
||||
<para><classname>ExitStatus</classname> is the return type of
|
||||
<methodname>afterStep</methodname> in order to allow listeners the
|
||||
@@ -649,12 +651,12 @@
|
||||
useful to perform logic before a chunk begins processing or after a
|
||||
chunk has completed:</para>
|
||||
|
||||
<programlisting><![CDATA[ public interface ChunkListener extends StepListener {
|
||||
<programlisting> public interface ChunkListener extends StepListener {
|
||||
|
||||
void beforeChunk();
|
||||
|
||||
void afterChunk();
|
||||
}]]></programlisting>
|
||||
}</programlisting>
|
||||
|
||||
<para>The <methodname>beforeChunk</methodname> method is called after
|
||||
the transaction is started, but before <methodname>read</methodname>
|
||||
@@ -683,14 +685,14 @@
|
||||
<para>When discussing skip logic above, it was mentioned that it may
|
||||
be beneficial to log out skipped records, so that they can be deal
|
||||
with later. In the case of read errors, this can be done with an
|
||||
<classname>ItemReaderListener:</classname><programlisting><![CDATA[ public interface ItemReadListener<T> extends StepListener {
|
||||
<classname>ItemReaderListener:</classname><programlisting> public interface ItemReadListener<T> extends StepListener {
|
||||
|
||||
void beforeRead();
|
||||
|
||||
void afterRead(T item);
|
||||
|
||||
void onReadError(Exception ex);
|
||||
}]]></programlisting></para>
|
||||
}</programlisting></para>
|
||||
|
||||
<para>The <methodname>beforeRead</methodname> method will be called
|
||||
before each call to <methodname>read</methodname> on the
|
||||
@@ -725,14 +727,14 @@
|
||||
<para>Just as with the <classname>ItemReadListener</classname>, the
|
||||
processing of an item can be 'listened' to:</para>
|
||||
|
||||
<programlisting><![CDATA[ public interface ItemProcessListener<T, S> extends StepListener {
|
||||
<programlisting> public interface ItemProcessListener<T, S> extends StepListener {
|
||||
|
||||
void beforeProcess(T item);
|
||||
|
||||
void afterProcess(T item, S result);
|
||||
|
||||
void onProcessError(T item, Exception e);
|
||||
}]]></programlisting>
|
||||
}</programlisting>
|
||||
|
||||
<para>The <methodname>beforeProcess</methodname> method will be called
|
||||
before <methodname>process</methodname> on the
|
||||
@@ -767,14 +769,14 @@
|
||||
<para>The writing of an item can be 'listened' to with the
|
||||
<classname>ItemWriteListener</classname>:</para>
|
||||
|
||||
<programlisting><![CDATA[ public interface ItemWriteListener<S> extends StepListener {
|
||||
<programlisting> public interface ItemWriteListener<S> extends StepListener {
|
||||
|
||||
void beforeWrite(List<? extends S> items);
|
||||
void beforeWrite(List<? extends S> items);
|
||||
|
||||
void afterWrite(List<? extends S> items);
|
||||
void afterWrite(List<? extends S> items);
|
||||
|
||||
void onWriteError(Exception exception, List<? extends S> items);
|
||||
}]]></programlisting>
|
||||
void onWriteError(Exception exception, List<? extends S> items);
|
||||
}</programlisting>
|
||||
|
||||
<para>The <methodname>beforeWrite</methodname> method will be called
|
||||
before <methodname>write</methodname> on the
|
||||
@@ -814,8 +816,8 @@
|
||||
this reason, there is a separate interface for tracking skipped
|
||||
items:</para>
|
||||
|
||||
<programlisting><![CDATA[
|
||||
public interface SkipListener<T,S> extends StepListener {
|
||||
<programlisting>
|
||||
public interface SkipListener<T,S> extends StepListener {
|
||||
|
||||
void onSkipInRead(Throwable t);
|
||||
|
||||
@@ -824,7 +826,7 @@
|
||||
void onSkipInWrite(S item, Throwable t);
|
||||
}
|
||||
|
||||
]]></programlisting>
|
||||
</programlisting>
|
||||
|
||||
<para><methodname>onSkipInRead</methodname> will be called whenever an
|
||||
item is skipped while reading. It should be noted that rollbacks may
|
||||
@@ -900,10 +902,10 @@
|
||||
<classname>Tasklet</classname> object; no 'tasklet' element is needed
|
||||
within the 'step':</para>
|
||||
|
||||
<programlisting><![CDATA[
|
||||
<step id="step1" ]]><emphasis role="bold">tasklet="myTasklet"</emphasis><![CDATA[ />
|
||||
<programlisting>
|
||||
<step id="step1" <emphasis role="bold">tasklet="myTasklet"</emphasis> />
|
||||
|
||||
]]></programlisting>
|
||||
</programlisting>
|
||||
|
||||
<note>
|
||||
<para><classname>TaskletStep</classname> will automatically register the
|
||||
@@ -924,15 +926,15 @@
|
||||
this class without having to write an adapter for the
|
||||
<classname>Tasklet</classname> interface:</para>
|
||||
|
||||
<programlisting><![CDATA[
|
||||
<bean id="myTasklet" class="org.springframework.batch.core.step.tasklet.TaskletAdapter">
|
||||
<property name="targetObject">
|
||||
<bean class="org.mycompany.FooDao">
|
||||
</property>
|
||||
<property name="targetMethod" value-"updateFoo" />
|
||||
</bean>
|
||||
<programlisting>
|
||||
<bean id="myTasklet" class="org.springframework.batch.core.step.tasklet.TaskletAdapter">
|
||||
<property name="targetObject">
|
||||
<bean class="org.mycompany.FooDao">
|
||||
</property>
|
||||
<property name="targetMethod" value-"updateFoo" />
|
||||
</bean>
|
||||
|
||||
]]></programlisting>
|
||||
</programlisting>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
@@ -947,7 +949,7 @@
|
||||
project, is a <classname>Tasklet</classname> implementation with just
|
||||
such a responsibility:</para>
|
||||
|
||||
<programlisting><![CDATA[ public class FileDeletingTasklet implements Tasklet, InitializingBean {
|
||||
<programlisting> public class FileDeletingTasklet implements Tasklet, InitializingBean {
|
||||
|
||||
private Resource directory;
|
||||
|
||||
@@ -956,7 +958,7 @@
|
||||
Assert.state(dir.isDirectory());
|
||||
|
||||
File[] files = dir.listFiles();
|
||||
for (int i = 0; i < files.length; i++) {
|
||||
for (int i = 0; i < files.length; i++) {
|
||||
boolean deleted = files[i].delete();
|
||||
if (!deleted) {
|
||||
throw new UnexpectedJobExecutionException("Could not delete file " + files[i].getPath());
|
||||
@@ -972,7 +974,7 @@
|
||||
public void afterPropertiesSet() throws Exception {
|
||||
Assert.notNull(directory, "directory must be set");
|
||||
}
|
||||
}]]></programlisting>
|
||||
}</programlisting>
|
||||
|
||||
<para>The above <classname>Tasklet</classname> implementation will
|
||||
delete all files within a given directory. It should be noted that the
|
||||
@@ -980,22 +982,22 @@
|
||||
that is left is to reference the <classname>Tasklet</classname> from the
|
||||
<classname>Step</classname>:</para>
|
||||
|
||||
<programlisting><![CDATA[
|
||||
<job id="taskletJob">
|
||||
<step id="deleteFilesInDir" tasklet="fileDeletingTasklet"/>
|
||||
</job>
|
||||
<programlisting>
|
||||
<job id="taskletJob">
|
||||
<step id="deleteFilesInDir" tasklet="fileDeletingTasklet"/>
|
||||
</job>
|
||||
|
||||
<bean id="fileDeletingTasklet"
|
||||
class="org.springframework.batch.sample.tasklet.FileDeletingTasklet">
|
||||
<property name="directoryResource">
|
||||
<bean id="directory"
|
||||
class="org.springframework.core.io.FileSystemResource">
|
||||
<constructor-arg value="target/test-outputs/test-dir" />
|
||||
</bean>
|
||||
</property>
|
||||
</bean>
|
||||
<bean id="fileDeletingTasklet"
|
||||
class="org.springframework.batch.sample.tasklet.FileDeletingTasklet">
|
||||
<property name="directoryResource">
|
||||
<bean id="directory"
|
||||
class="org.springframework.core.io.FileSystemResource">
|
||||
<constructor-arg value="target/test-outputs/test-dir" />
|
||||
</bean>
|
||||
</property>
|
||||
</bean>
|
||||
|
||||
]]></programlisting>
|
||||
</programlisting>
|
||||
</section>
|
||||
</section>
|
||||
|
||||
@@ -1032,18 +1034,18 @@
|
||||
<para>This can be achieved using the 'next' attribute of the step
|
||||
element:</para>
|
||||
|
||||
<para><programlisting><![CDATA[
|
||||
<job id="job">
|
||||
<step id="stepA" next="stepB" />
|
||||
<step id="stepB" next="stepC"/>
|
||||
<step id="stepC" />
|
||||
</job>
|
||||
<para><programlisting>
|
||||
<job id="job">
|
||||
<step id="stepA" next="stepB" />
|
||||
<step id="stepB" next="stepC"/>
|
||||
<step id="stepC" />
|
||||
</job>
|
||||
|
||||
]]></programlisting>In the scenario above, 'step A' will execute first because
|
||||
it is the first <classname>Step</classname> listed. If 'step A'
|
||||
completes normally, then 'step B' will execute, and so on. However, if
|
||||
'step A' fails, then the entire <classname>Job</classname> will fail and
|
||||
'step B' will not execute.</para>
|
||||
</programlisting>In the scenario above, 'step A' will execute first because it
|
||||
is the first <classname>Step</classname> listed. If 'step A' completes
|
||||
normally, then 'step B' will execute, and so on. However, if 'step A'
|
||||
fails, then the entire <classname>Job</classname> will fail and 'step B'
|
||||
will not execute.</para>
|
||||
|
||||
<note>
|
||||
<para>With the Spring Batch namespace, the first step listed in the
|
||||
@@ -1101,17 +1103,17 @@
|
||||
<para>The next element specifies a pattern to match and the step to
|
||||
execute next:</para>
|
||||
|
||||
<para><programlisting><![CDATA[
|
||||
<job id="job">
|
||||
<step id="stepA">
|
||||
<next on="FAILED" to="stepB" />
|
||||
<next on="*" to="stepC" />
|
||||
</step>
|
||||
<step id="stepB" next="stepC" />
|
||||
<step id="stepC" />
|
||||
</job>
|
||||
<para><programlisting>
|
||||
<job id="job">
|
||||
<step id="stepA">
|
||||
<next on="FAILED" to="stepB" />
|
||||
<next on="*" to="stepC" />
|
||||
</step>
|
||||
<step id="stepB" next="stepC" />
|
||||
<step id="stepC" />
|
||||
</job>
|
||||
|
||||
]]></programlisting></para>
|
||||
</programlisting></para>
|
||||
|
||||
<para>The "on" attribute of a transition element uses a simple
|
||||
pattern-matching scheme to match the <classname>ExitStatus</classname>
|
||||
@@ -1159,10 +1161,10 @@
|
||||
it fails, and so on. The example above contains the following 'next'
|
||||
element:</para>
|
||||
|
||||
<programlisting><![CDATA[
|
||||
<next on="FAILED" to="stepB" />
|
||||
<programlisting>
|
||||
<next on="FAILED" to="stepB" />
|
||||
|
||||
]]></programlisting>
|
||||
</programlisting>
|
||||
|
||||
<para>At first glance, it would appear that the 'on' attribute
|
||||
references the <classname>BatchStatus</classname> of the
|
||||
@@ -1179,14 +1181,14 @@
|
||||
code needs to be different? A good example comes from the skip sample
|
||||
job within the samples project:</para>
|
||||
|
||||
<programlisting><![CDATA[
|
||||
<step id="step1">
|
||||
<end on="FAILED" />
|
||||
<next on="COMPLETED WITH SKIPS" to="errorPrint1" />
|
||||
<next on="*" to="step2" />
|
||||
</step>
|
||||
<programlisting>
|
||||
<step id="step1">
|
||||
<end on="FAILED" />
|
||||
<next on="COMPLETED WITH SKIPS" to="errorPrint1" />
|
||||
<next on="*" to="step2" />
|
||||
</step>
|
||||
|
||||
]]></programlisting>
|
||||
</programlisting>
|
||||
|
||||
<para>The above step has three possibilities:</para>
|
||||
|
||||
@@ -1212,18 +1214,18 @@
|
||||
change the exit code based on the condition of the execution having
|
||||
skipped records:</para>
|
||||
|
||||
<programlisting><![CDATA[ public class SkipCheckingListener extends StepExecutionListenerSupport {
|
||||
<programlisting> public class SkipCheckingListener extends StepExecutionListenerSupport {
|
||||
|
||||
public ExitStatus afterStep(StepExecution stepExecution) {
|
||||
if (!stepExecution.getExitStatus().getExitCode().equals(ExitStatus.FAILED.getExitCode())
|
||||
&& stepExecution.getSkipCount() > 0) {
|
||||
&& stepExecution.getSkipCount() > 0) {
|
||||
return new ExitStatus("COMPLETED WITH SKIPS");
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
}]]></programlisting>
|
||||
}</programlisting>
|
||||
|
||||
<para>The above code is a <classname>StepExecutionListener</classname>
|
||||
that first checks to make sure the <classname>Step</classname> was
|
||||
@@ -1251,7 +1253,7 @@
|
||||
after the following step executes, the <classname>Job</classname> will
|
||||
end:</para>
|
||||
|
||||
<para><programlisting><![CDATA[ <step id="stepC" />]]></programlisting></para>
|
||||
<para><programlisting> <step id="stepC" /></programlisting></para>
|
||||
|
||||
<para>If no transitions are defined for a <classname>Step</classname>,
|
||||
then the <classname>Job</classname>'s statuses will be defined as
|
||||
@@ -1310,12 +1312,12 @@
|
||||
fails, the <classname>Job</classname> will not be restartable (because
|
||||
the status is COMPLETED).</para>
|
||||
|
||||
<programlisting><![CDATA[ <step id="step1" next="step2">
|
||||
<step id="step2">
|
||||
<end on="FAILED"/>
|
||||
<next on="*" to="step3"/>
|
||||
</step>
|
||||
<step id="step3">]]></programlisting>
|
||||
<programlisting> <step id="step1" next="step2">
|
||||
<step id="step2">
|
||||
<end on="FAILED"/>
|
||||
<next on="*" to="step3"/>
|
||||
</step>
|
||||
<step id="step3"></programlisting>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
@@ -1339,12 +1341,12 @@
|
||||
Additionally, if step2 fails, and the <classname>Job</classname> is
|
||||
restarted, then execution will begin again on step2.</para>
|
||||
|
||||
<programlisting><![CDATA[ <step id="step1" next="step2">
|
||||
<step id="step2">
|
||||
<fail on="FAILED" exit-code="EARLY TERMINATION"/>
|
||||
<next on="*" to="step3"/>
|
||||
</step>
|
||||
<step id="step3">]]></programlisting>
|
||||
<programlisting> <step id="step1" next="step2">
|
||||
<step id="step2">
|
||||
<fail on="FAILED" exit-code="EARLY TERMINATION"/>
|
||||
<next on="*" to="step3"/>
|
||||
</step>
|
||||
<step id="step3"></programlisting>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
@@ -1362,10 +1364,10 @@
|
||||
the job will then stop. Once it is restarted, execution will begin on
|
||||
step2.</para>
|
||||
|
||||
<para><programlisting><![CDATA[ <step id="step1">
|
||||
<stop on="COMPLETED" restart="step2"/>
|
||||
</step>
|
||||
<step id="step2"/>]]></programlisting></para>
|
||||
<para><programlisting> <step id="step1">
|
||||
<stop on="COMPLETED" restart="step2"/>
|
||||
</step>
|
||||
<step id="step2"/></programlisting></para>
|
||||
</section>
|
||||
</section>
|
||||
|
||||
@@ -1378,7 +1380,7 @@
|
||||
<classname>JobExecutionDecider</classname> can be used to assist in the
|
||||
decision.</para>
|
||||
|
||||
<para><programlisting><![CDATA[
|
||||
<para><programlisting>
|
||||
public class MyDecider implements JobExecutionDecider {
|
||||
|
||||
public String decide(JobExecution jobExecution, StepExecution stepExecution) {
|
||||
@@ -1392,27 +1394,27 @@
|
||||
|
||||
}
|
||||
|
||||
]]></programlisting></para>
|
||||
</programlisting></para>
|
||||
|
||||
<para>In the job configuration, a "decision" tag will specify the
|
||||
decider to use as well as all of the transitions.</para>
|
||||
|
||||
<para><programlisting><![CDATA[
|
||||
<job id="job">
|
||||
<step id="step1" next="decision" />
|
||||
<para><programlisting>
|
||||
<job id="job">
|
||||
<step id="step1" next="decision" />
|
||||
|
||||
<decision id="skipCheckingDecision" decider="decider">
|
||||
<next on="FAILED" to="step2" />
|
||||
<next on="COMPLETED" to="step3" />
|
||||
</step>
|
||||
<decision id="skipCheckingDecision" decider="decider">
|
||||
<next on="FAILED" to="step2" />
|
||||
<next on="COMPLETED" to="step3" />
|
||||
</step>
|
||||
|
||||
<step id="step2" next="step3"/>
|
||||
<step id="step3" />
|
||||
</job>
|
||||
<step id="step2" next="step3"/>
|
||||
<step id="step3" />
|
||||
</job>
|
||||
|
||||
<bean id="decider" class="com.MyDecider"/>
|
||||
<bean id="decider" class="com.MyDecider"/>
|
||||
|
||||
]]></programlisting></para>
|
||||
</programlisting></para>
|
||||
</section>
|
||||
|
||||
<section id="split-flows">
|
||||
@@ -1429,16 +1431,16 @@
|
||||
elements such as the 'next' attribute or the 'next', 'end', 'fail', or
|
||||
'pause' elements.</para>
|
||||
|
||||
<programlisting><![CDATA[ <split id="split1" next="step4">
|
||||
<flow>
|
||||
<step id="step1" next="step2"/>
|
||||
<step id="step2"/>
|
||||
</flow>
|
||||
<flow>
|
||||
<step id="step3"/>
|
||||
</flow>
|
||||
</split>
|
||||
<step id="step4"/>]]></programlisting>
|
||||
<programlisting> <split id="split1" next="step4">
|
||||
<flow>
|
||||
<step id="step1" next="step2"/>
|
||||
<step id="step2"/>
|
||||
</flow>
|
||||
<flow>
|
||||
<step id="step3"/>
|
||||
</flow>
|
||||
</split>
|
||||
<step id="step4"/></programlisting>
|
||||
</section>
|
||||
</section>
|
||||
|
||||
@@ -1452,14 +1454,14 @@
|
||||
Flat File resources can be configured using standard Spring
|
||||
constructs:</para>
|
||||
|
||||
<programlisting><![CDATA[
|
||||
<bean id="flatFileItemReader"
|
||||
class="org.springframework.batch.item.file.FlatFileItemReader">
|
||||
<property name="resource"
|
||||
value="file://outputs/20070122.testStream.CustomerReportStep.TEMP.txt" />
|
||||
</bean>
|
||||
<programlisting>
|
||||
<bean id="flatFileItemReader"
|
||||
class="org.springframework.batch.item.file.FlatFileItemReader">
|
||||
<property name="resource"
|
||||
value="file://outputs/20070122.testStream.CustomerReportStep.TEMP.txt" />
|
||||
</bean>
|
||||
|
||||
]]></programlisting>
|
||||
</programlisting>
|
||||
|
||||
<para>The above <classname>Resource</classname> will load the file from
|
||||
the file system location specified. Note that absolute locations have to
|
||||
@@ -1469,13 +1471,13 @@
|
||||
at runtime as a parameter to the job. This could be solved using '-D'
|
||||
parameters, i.e. a system property:</para>
|
||||
|
||||
<programlisting><![CDATA[
|
||||
<bean id="flatFileItemReader"
|
||||
class="org.springframework.batch.item.file.FlatFileItemReader">
|
||||
<property name="resource" value="${input.file.name}" />
|
||||
</bean>
|
||||
<programlisting>
|
||||
<bean id="flatFileItemReader"
|
||||
class="org.springframework.batch.item.file.FlatFileItemReader">
|
||||
<property name="resource" value="${input.file.name}" />
|
||||
</bean>
|
||||
|
||||
]]></programlisting>
|
||||
</programlisting>
|
||||
|
||||
<para>All that would be required for this solution to work would be a
|
||||
system argument (-Dinput.file.name="file://file.txt"). (Note that although
|
||||
@@ -1491,34 +1493,34 @@
|
||||
accomplish this, Spring Batch allows for the late binding of various Job
|
||||
and Step attributes:</para>
|
||||
|
||||
<programlisting><![CDATA[
|
||||
<bean id="flatFileItemReader" scope="step"
|
||||
class="org.springframework.batch.item.file.FlatFileItemReader">
|
||||
<property name="resource" value="]]><emphasis role="bold">#{jobParameters[input.file.name]}</emphasis><![CDATA[" />
|
||||
</bean>
|
||||
<programlisting>
|
||||
<bean id="flatFileItemReader" scope="step"
|
||||
class="org.springframework.batch.item.file.FlatFileItemReader">
|
||||
<property name="resource" value="<emphasis role="bold">#{jobParameters[input.file.name]}</emphasis>" />
|
||||
</bean>
|
||||
|
||||
]]></programlisting>
|
||||
</programlisting>
|
||||
|
||||
<para>Both the <classname>JobExecution</classname> and
|
||||
<classname>StepExecution</classname> level
|
||||
<classname>ExecutionContext</classname> can be accessed in the same
|
||||
way:</para>
|
||||
|
||||
<programlisting><![CDATA[
|
||||
<bean id="flatFileItemReader" scope="step"
|
||||
class="org.springframework.batch.item.file.FlatFileItemReader">
|
||||
<property name="resource" value="]]><emphasis role="bold">#{jobExecutionContext[input.file.name]}</emphasis><![CDATA[" />
|
||||
</bean>
|
||||
<programlisting>
|
||||
<bean id="flatFileItemReader" scope="step"
|
||||
class="org.springframework.batch.item.file.FlatFileItemReader">
|
||||
<property name="resource" value="<emphasis role="bold">#{jobExecutionContext[input.file.name]}</emphasis>" />
|
||||
</bean>
|
||||
|
||||
]]></programlisting>
|
||||
</programlisting>
|
||||
|
||||
<programlisting><![CDATA[
|
||||
<bean id="flatFileItemReader" scope="step"
|
||||
class="org.springframework.batch.item.file.FlatFileItemReader">
|
||||
<property name="resource" value="]]><emphasis role="bold">#{stepExecutionContext[input.file.name]}</emphasis><![CDATA[" />
|
||||
</bean>
|
||||
<programlisting>
|
||||
<bean id="flatFileItemReader" scope="step"
|
||||
class="org.springframework.batch.item.file.FlatFileItemReader">
|
||||
<property name="resource" value="<emphasis role="bold">#{stepExecutionContext[input.file.name]}</emphasis>" />
|
||||
</bean>
|
||||
|
||||
]]></programlisting>
|
||||
</programlisting>
|
||||
|
||||
<section id="step-scope">
|
||||
<title>Step Scope</title>
|
||||
@@ -1526,37 +1528,37 @@
|
||||
<para>All of the late binding examples from above have a scope of "step"
|
||||
declared on the bean definition:</para>
|
||||
|
||||
<programlisting><![CDATA[
|
||||
<bean id="flatFileItemReader" ]]><emphasis role="bold">scope="step"</emphasis><![CDATA[
|
||||
class="org.springframework.batch.item.file.FlatFileItemReader">
|
||||
<property name="resource" value="#{jobParameters[input.file.name]}" />
|
||||
</bean>
|
||||
<programlisting>
|
||||
<bean id="flatFileItemReader" <emphasis role="bold">scope="step"</emphasis>
|
||||
class="org.springframework.batch.item.file.FlatFileItemReader">
|
||||
<property name="resource" value="#{jobParameters[input.file.name]}" />
|
||||
</bean>
|
||||
|
||||
]]></programlisting>
|
||||
</programlisting>
|
||||
|
||||
<para>Using a scope of <classname>Step</classname> is required in order
|
||||
to use late binding since the bean cannot actually be instantiated until
|
||||
the <classname>Step</classname> starts, which allows the attributes to
|
||||
be found. Because it is not part of the Spring container by default, it
|
||||
must be added explicitly, either by using the <literal>batch</literal>
|
||||
namespace: </para>
|
||||
must be added explicitly, either by using the <literal>batch</literal>
|
||||
namespace:</para>
|
||||
|
||||
<programlisting><![CDATA[
|
||||
<beans xmlns="http://www.springframework.org/schema/beans"
|
||||
<programlisting>
|
||||
<beans xmlns="http://www.springframework.org/schema/beans"
|
||||
xmlns:batch="http://www.springframework.org/schema/batch"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="...">
|
||||
xsi:schemaLocation="...">
|
||||
...
|
||||
</beans>
|
||||
]]></programlisting>
|
||||
</beans>
|
||||
</programlisting>
|
||||
|
||||
<para>or by including a bean definition explicitly for the<classname>Step</classname> (but not both):</para>
|
||||
<para>or by including a bean definition explicitly for
|
||||
the<classname>Step</classname> (but not both):</para>
|
||||
|
||||
<programlisting><![CDATA[
|
||||
<bean class="org.springframework.batch.core.scope.StepScope" />
|
||||
|
||||
]]></programlisting>
|
||||
<programlisting>
|
||||
<bean class="org.springframework.batch.core.scope.StepScope" />
|
||||
|
||||
</programlisting>
|
||||
</section>
|
||||
</section>
|
||||
</chapter>
|
||||
|
||||
Reference in New Issue
Block a user