288 lines
13 KiB
XML
288 lines
13 KiB
XML
<?xml version="1.0" encoding="UTF-8"?>
|
|
<!DOCTYPE chapter PUBLIC "-//OASIS//DTD DocBook XML V4.4//EN"
|
|
"http://www.oasis-open.org/docbook/xml/4.4/docbookx.dtd">
|
|
<chapter id="repeat">
|
|
<title>Repeat</title>
|
|
|
|
<section id="repeatTemplate">
|
|
<title>RepeatTemplate</title>
|
|
|
|
<para>Batch processing is about repetitive actions - either as a simple
|
|
optimization, or as part of a job. To strategize and generalize the
|
|
repetition as well as to provide what amounts to an iterator framework,
|
|
Spring Batch has the <classname>RepeatOperations</classname> interface.
|
|
The <classname>RepeatOperations</classname> interface looks like
|
|
this:</para>
|
|
|
|
<programlisting language="java">public interface RepeatOperations {
|
|
|
|
RepeatStatus iterate(RepeatCallback callback) throws RepeatException;
|
|
|
|
}</programlisting>
|
|
<para>The callback is a simple interface that allows you to insert
|
|
some business logic to be repeated:</para>
|
|
|
|
<programlisting language="java">public interface RepeatCallback {
|
|
|
|
RepeatStatus doInIteration(RepeatContext context) throws Exception;
|
|
|
|
}</programlisting>
|
|
<para>The callback is executed repeatedly until the implementation
|
|
decides that the iteration should end. The return value in these
|
|
interfaces is an enumeration that can either be
|
|
<code>RepeatStatus.CONTINUABLE</code> or
|
|
<code>RepeatStatus.FINISHED</code>. A <classname>RepeatStatus</classname>
|
|
conveys information to the caller of the repeat operations about whether
|
|
there is any more work to do. Generally speaking, implementations of
|
|
<classname>RepeatOperations</classname> should inspect the
|
|
<classname>RepeatStatus</classname> and use it as part of the decision to
|
|
end the iteration. Any callback that wishes to signal to the caller that
|
|
there is no more work to do can return
|
|
<code>RepeatStatus.FINISHED</code>.</para>
|
|
|
|
<para>The simplest general purpose implementation of
|
|
<classname>RepeatOperations</classname> is
|
|
<classname>RepeatTemplate</classname>. It could be used like this:</para>
|
|
|
|
<programlisting language="java">RepeatTemplate template = new RepeatTemplate();
|
|
|
|
template.setCompletionPolicy(new FixedChunkSizeCompletionPolicy(2));
|
|
|
|
template.iterate(new RepeatCallback() {
|
|
|
|
public ExitStatus doInIteration(RepeatContext context) {
|
|
// Do stuff in batch...
|
|
return ExitStatus.CONTINUABLE;
|
|
}
|
|
|
|
});</programlisting>
|
|
|
|
<para>In the example we return <code>RepeatStatus.CONTINUABLE</code> to
|
|
show that there is more work to do. The callback can also return
|
|
<code>ExitStatus.FINISHED</code> if it wants to signal to the caller that
|
|
there is no more work to do. Some iterations can be terminated by
|
|
considerations intrinsic to the work being done in the callback, others
|
|
are effectively infinite loops as far as the callback is concerned and the
|
|
completion decision is delegated to an external policy as in the case
|
|
above.</para>
|
|
|
|
<section id="repeatContext">
|
|
<title>RepeatContext</title>
|
|
|
|
<para>The method parameter for the <classname>RepeatCallback</classname>
|
|
is a <classname>RepeatContext</classname>. Many callbacks will simply
|
|
ignore the context, but if necessary it can be used as an attribute bag
|
|
to store transient data for the duration of the iteration. After the
|
|
<methodname>iterate</methodname> method returns, the context will no
|
|
longer exist.</para>
|
|
|
|
<para>A <classname>RepeatContext</classname> will have a parent context
|
|
if there is a nested iteration in progress. The parent context is
|
|
occasionally useful for storing data that need to be shared between
|
|
calls to <methodname>iterate</methodname>. This is the case for instance
|
|
if you want to count the number of occurrences of an event in the
|
|
iteration and remember it across subsequent calls.</para>
|
|
</section>
|
|
|
|
<section id="repeatStatus">
|
|
<title>RepeatStatus</title>
|
|
|
|
<para><classname>RepeatStatus</classname> is an enumeration used by
|
|
Spring Batch to indicate whether processing has finished. These are
|
|
possible <classname>RepeatStatus</classname> values:</para>
|
|
|
|
<table>
|
|
<title>ExitStatus Properties</title>
|
|
|
|
<tgroup cols="2">
|
|
<tbody>
|
|
<row>
|
|
<entry><emphasis role="bold">Value</emphasis></entry>
|
|
|
|
<entry><emphasis role="bold">Description</emphasis></entry>
|
|
</row>
|
|
|
|
<row>
|
|
<entry>CONTINUABLE</entry>
|
|
|
|
<entry>There is more work to do.</entry>
|
|
</row>
|
|
|
|
<row>
|
|
<entry>FINISHED</entry>
|
|
|
|
<entry>No more repetitions should take place.</entry>
|
|
</row>
|
|
</tbody>
|
|
</tgroup>
|
|
</table>
|
|
|
|
<para><classname>RepeatStatus</classname> values can also be combined
|
|
with a logical AND operation using the <methodname>and</methodname>()
|
|
method in <classname>RepeatStatus</classname>. The effect of this is to
|
|
do a logical AND on the continuable flag. In other words, if either
|
|
status is <code>FINISHED</code>, then the result will be
|
|
<code>FINISHED</code>.</para>
|
|
</section>
|
|
</section>
|
|
|
|
<section id="completionPolicies">
|
|
<title>Completion Policies</title>
|
|
|
|
<para>Inside a <classname>RepeatTemplate</classname> the termination of
|
|
the loop in the <methodname>iterate</methodname> method is determined by a
|
|
<classname>CompletionPolicy</classname> which is also a factory for the
|
|
<classname>RepeatContext</classname>. The
|
|
<classname>RepeatTemplate</classname> has the responsibility to use the
|
|
current policy to create a <classname>RepeatContext</classname> and pass
|
|
that in to the <classname>RepeatCallback</classname> at every stage in the
|
|
iteration. After a callback completes its
|
|
<methodname>doInIteration</methodname>, the
|
|
<classname>RepeatTemplate</classname> has to make a call to the
|
|
<classname>CompletionPolicy</classname> to ask it to update its state
|
|
(which will be stored in the <classname>RepeatContext</classname>). Then
|
|
it asks the policy if the iteration is complete.</para>
|
|
|
|
<para>Spring Batch provides some simple general purpose implementations of
|
|
<classname>CompletionPolicy</classname>. The
|
|
<classname>SimpleCompletionPolicy</classname> just allows an execution up
|
|
to a fixed number of times (with <code>RepeatStatus.FINISHED</code>
|
|
forcing early completion at any time).</para>
|
|
|
|
<para>Users might need to implement their own completion policies for more
|
|
complicated decisions. For example, a batch processing window that
|
|
prevents batch jobs from executing once the online systems are in use
|
|
would require a custom policy.</para>
|
|
</section>
|
|
|
|
<section id="repeatExceptionHandling">
|
|
<title>Exception Handling</title>
|
|
|
|
<para>If there is an exception thrown inside a
|
|
<classname>RepeatCallback</classname>, the
|
|
<classname>RepeatTemplate</classname> consults an
|
|
<classname>ExceptionHandler</classname> which can decide whether or not to
|
|
re-throw the exception.</para>
|
|
|
|
<programlisting language="java">public interface ExceptionHandler {
|
|
|
|
void handleException(RepeatContext context, Throwable throwable)
|
|
throws RuntimeException;
|
|
|
|
}</programlisting>
|
|
<para>A common use case is to count the number of exceptions of a
|
|
given type, and fail when a limit is reached. For this purpose Spring
|
|
Batch provides the <classname>SimpleLimitExceptionHandler</classname> and
|
|
slightly more flexible
|
|
<classname>RethrowOnThresholdExceptionHandler</classname>. The
|
|
<classname>SimpleLimitExceptionHandler</classname> has a limit property
|
|
and an exception type that should be compared with the current exception -
|
|
all subclasses of the provided type are also counted. Exceptions of the
|
|
given type are ignored until the limit is reached, and then rethrown.
|
|
Those of other types are always rethrown.</para>
|
|
|
|
<para>An important optional property of the
|
|
<classname>SimpleLimitExceptionHandler</classname> is the boolean flag
|
|
<code>useParent</code>. It is false by default, so the limit is only
|
|
accounted for in the current <classname>RepeatContext</classname>. When
|
|
set to true, the limit is kept across sibling contexts in a nested
|
|
iteration (e.g. a set of chunks inside a step).</para>
|
|
</section>
|
|
|
|
<section id="repeatListeners">
|
|
<title>Listeners</title>
|
|
|
|
<para>Often it is useful to be able to receive additional callbacks for
|
|
cross cutting concerns across a number of different iterations. For this
|
|
purpose Spring Batch provides the <classname>RepeatListener</classname>
|
|
interface. The <classname>RepeatTemplate</classname> allows users to
|
|
register <classname>RepeatListener</classname>s, and they will be given
|
|
callbacks with the <classname>RepeatContext</classname> and
|
|
<classname>RepeatStatus</classname> where available during the
|
|
iteration.</para>
|
|
|
|
<para>The interface looks like this:</para>
|
|
|
|
<programlisting language="java">public interface RepeatListener {
|
|
void before(RepeatContext context);
|
|
void after(RepeatContext context, RepeatStatus result);
|
|
void open(RepeatContext context);
|
|
void onError(RepeatContext context, Throwable e);
|
|
void close(RepeatContext context);
|
|
}</programlisting>
|
|
<para>The <methodname>open</methodname> and
|
|
<methodname>close</methodname> callbacks come before and after the entire
|
|
iteration. <methodname>before</methodname>, <methodname>after</methodname>
|
|
and <methodname>onError</methodname> apply to the individual
|
|
RepeatCallback calls.</para>
|
|
|
|
<para>Note that when there is more than one listener, they are in a list,
|
|
so there is an order. In this case <methodname>open</methodname> and
|
|
<methodname>before</methodname> are called in the same order while
|
|
<methodname>after</methodname>, <methodname>onError</methodname> and
|
|
<methodname>close</methodname> are called in reverse order.</para>
|
|
</section>
|
|
|
|
<section id="repeatParallelProcessing">
|
|
<title>Parallel Processing</title>
|
|
|
|
<para>Implementations of <classname>RepeatOperations</classname> are not
|
|
restricted to executing the callback sequentially. It is quite important
|
|
that some implementations are able to execute their callbacks in parallel.
|
|
To this end, Spring Batch provides the
|
|
<classname>TaskExecutorRepeatTemplate</classname>, which uses the Spring
|
|
<classname>TaskExecutor</classname> strategy to run the
|
|
<classname>RepeatCallback</classname>. The default is to use a
|
|
<classname>SynchronousTaskExecutor</classname>, which has the effect of
|
|
executing the whole iteration in the same thread (the same as a normal
|
|
<classname>RepeatTemplate</classname>).</para>
|
|
</section>
|
|
|
|
<section id="declarativeIteration">
|
|
<title>Declarative Iteration</title>
|
|
|
|
<para>Sometimes there is some business processing that you know you want
|
|
to repeat every time it happens. The classic example of this is the
|
|
optimization of a message pipeline - it is more efficient to process a
|
|
batch of messages, if they are arriving frequently, than to bear the cost
|
|
of a separate transaction for every message. Spring Batch provides an AOP
|
|
interceptor that wraps a method call in a
|
|
<classname>RepeatOperations</classname> for just this purpose. The
|
|
<classname>RepeatOperationsInterceptor</classname> executes the
|
|
intercepted method and repeats according to the
|
|
<classname>CompletionPolicy</classname> in the provided
|
|
<classname>RepeatTemplate</classname>.</para>
|
|
|
|
<para>Here is an example of declarative iteration using the Spring AOP
|
|
namespace to repeat a service call to a method called
|
|
<methodname>processMessage</methodname> (for more detail on how to
|
|
configure AOP interceptors see the Spring User Guide):</para>
|
|
|
|
<programlisting language="xml"><aop:config>
|
|
<aop:pointcut id="transactional"
|
|
expression="execution(* com..*Service.processMessage(..))" />
|
|
<aop:advisor pointcut-ref="transactional"
|
|
advice-ref="retryAdvice" order="-1"/>
|
|
</aop:config>
|
|
|
|
<bean id="retryAdvice" class="org.spr...RepeatOperationsInterceptor"/></programlisting>
|
|
|
|
<para>The example above uses a default
|
|
<classname>RepeatTemplate</classname> inside the interceptor. To change
|
|
the policies, listeners etc. you only need to inject an instance of
|
|
<classname>RepeatTemplate</classname> into the interceptor.</para>
|
|
|
|
<para>If the intercepted method returns <code>void</code> then the
|
|
interceptor always returns ExitStatus.CONTINUABLE (so there is a danger of
|
|
an infinite loop if the <classname>CompletionPolicy</classname> does not
|
|
have a finite end point). Otherwise it returns
|
|
<code>ExitStatus.CONTINUABLE</code> until the return value from the
|
|
intercepted method is null, at which point it returns
|
|
<code>ExitStatus.FINISHED</code>. So the business logic inside the target
|
|
method can signal that there is no more work to do by returning
|
|
<code>null</code>, or by throwing an exception that is re-thrown by the
|
|
<classname>ExceptionHandler</classname> in the provided
|
|
<classname>RepeatTemplate</classname>.</para>
|
|
</section>
|
|
</chapter>
|