Files
spring-batch/build/reference/html/springBatchIntegration.html
Michael Minella 75ab909314 update
2017-03-23 10:18:33 -05:00

644 lines
55 KiB
HTML

<html><head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>13.&nbsp;Spring Batch Integration</title><link rel="stylesheet" type="text/css" href="css/manual-multipage.css"><meta name="generator" content="DocBook XSL Stylesheets V1.78.1"><link rel="home" href="index.html" title="Spring Batch - Reference Documentation"><link rel="up" href="index.html" title="Spring Batch - Reference Documentation"><link rel="prev" href="jsr-352.html" title="12.&nbsp;JSR-352 Support"><link rel="next" href="listOfReadersAndWriters.html" title="Appendix&nbsp;A.&nbsp;List of ItemReaders and ItemWriters"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">13.&nbsp;Spring Batch Integration</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="jsr-352.html">Prev</a>&nbsp;</td><th width="60%" align="center">&nbsp;</th><td width="20%" align="right">&nbsp;<a accesskey="n" href="listOfReadersAndWriters.html">Next</a></td></tr></table><hr></div><div class="chapter"><div class="titlepage"><div><div><h1 class="title"><a name="springBatchIntegration" href="#springBatchIntegration"></a>13.&nbsp;Spring Batch Integration</h1></div></div></div><div class="sect1"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="spring-batch-integration-introduction" href="#spring-batch-integration-introduction"></a>13.1.&nbsp;Spring Batch Integration Introduction</h2></div></div></div><p>
Many users of Spring Batch may encounter requirements that are
outside the scope of Spring Batch, yet may be efficiently and
concisely implemented using Spring Integration. Conversely, Spring
Batch users may encounter Spring Batch requirements and need a way
to efficiently integrate both frameworks. In this context several
patterns and use-cases emerge and Spring Batch Integration will
address those requirements.
</p><p>
The line between Spring Batch and Spring Integration is not always
clear, but there are guidelines that one can follow. Principally,
these are: think about granularity, and apply common patterns. Some
of those common patterns are described in this reference manual
section.
</p><p>
Adding messaging to a batch process enables automation of
operations, and also separation and strategizing of key concerns.
For example a message might trigger a job to execute, and then the
sending of the message can be exposed in a variety of ways. Or when
a job completes or fails that might trigger a message to be sent,
and the consumers of those messages might have operational concerns
that have nothing to do with the application itself. Messaging can
also be embedded in a job, for example reading or writing items for
processing via channels. Remote partitioning and remote chunking
provide methods to distribute workloads over an number of workers.
</p><p>
Some key concepts that we will cover are:
</p><div class="itemizedlist"><ul class="itemizedlist" style="list-style-type: disc; "><li class="listitem"><p>
<a class="link" href="springBatchIntegration.html#namespace-support" title="13.1.1.&nbsp;Namespace Support">Namespace Support</a>
</p></li><li class="listitem"><p>
<a class="link" href="springBatchIntegration.html#launching-batch-jobs-through-messages" title="13.1.2.&nbsp;Launching Batch Jobs through Messages">Launching
Batch Jobs through Messages</a>
</p></li><li class="listitem"><p>
<a class="link" href="springBatchIntegration.html#providing-feedback-with-informational-messages" title="13.1.3.&nbsp;Providing Feedback with Informational Messages">Providing
Feedback with Informational Messages</a>
</p></li><li class="listitem"><p>
<a class="link" href="springBatchIntegration.html#asynchronous-processors" title="13.1.4.&nbsp;Asynchronous Processors">Asynchronous
Processors</a>
</p></li><li class="listitem"><p>
<a class="link" href="springBatchIntegration.html#externalizing-batch-process-execution" title="13.1.5.&nbsp;Externalizing Batch Process Execution">Externalizing
Batch Process Execution</a>
</p></li></ul></div><div class="sect2"><div class="titlepage"><div><div><h3 class="title"><a name="namespace-support" href="#namespace-support"></a>13.1.1.&nbsp;Namespace Support</h3></div></div></div><p>
Since Spring Batch Integration 1.3, dedicated XML Namespace
support was added, with the aim to provide an easier configuration
experience. In order to activate the namespace, add the following
namespace declarations to your Spring XML Application Context
file:
</p><pre class="programlisting"><span class="hl-tag">&lt;beans</span> <span class="hl-attribute">xmlns</span>=<span class="hl-value">"http://www.springframework.org/schema/beans"</span>
<span class="hl-attribute">xmlns:xsi</span>=<span class="hl-value">"http://www.w3.org/2001/XMLSchema-instance"</span>
<span class="hl-attribute">xmlns:batch-int</span>=<span class="hl-value">"http://www.springframework.org/schema/batch-integration"</span>
<span class="hl-attribute">xsi:schemaLocation</span>=<span class="hl-value">"
http://www.springframework.org/schema/batch-integration
http://www.springframework.org/schema/batch-integration/spring-batch-integration.xsd"</span><span class="hl-tag">&gt;</span>
...
<span class="hl-tag">&lt;/beans&gt;</span></pre><p>
A fully configured Spring XML Application Context file for Spring
Batch Integration may look like the following:
</p><pre class="programlisting"><span class="hl-tag">&lt;beans</span> <span class="hl-attribute">xmlns</span>=<span class="hl-value">"http://www.springframework.org/schema/beans"</span>
<span class="hl-attribute">xmlns:xsi</span>=<span class="hl-value">"http://www.w3.org/2001/XMLSchema-instance"</span>
<span class="hl-attribute">xmlns:int</span>=<span class="hl-value">"http://www.springframework.org/schema/integration"</span>
<span class="hl-attribute">xmlns:batch</span>=<span class="hl-value">"http://www.springframework.org/schema/batch"</span>
<span class="hl-attribute">xmlns:batch-int</span>=<span class="hl-value">"http://www.springframework.org/schema/batch-integration"</span>
<span class="hl-attribute">xsi:schemaLocation</span>=<span class="hl-value">"
http://www.springframework.org/schema/batch-integration
http://www.springframework.org/schema/batch-integration/spring-batch-integration.xsd
http://www.springframework.org/schema/batch
http://www.springframework.org/schema/batch/spring-batch.xsd
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/integration
http://www.springframework.org/schema/integration/spring-integration.xsd"</span><span class="hl-tag">&gt;</span>
...
<span class="hl-tag">&lt;/beans&gt;</span></pre><p>
Appending version numbers to the referenced XSD file is also
allowed but, as a version-less declaration will always use the
latest schema, we generally don't recommend appending the version
number to the XSD name. Adding a version number, for instance,
would create possibly issues when updating the Spring Batch
Integration dependencies as they may require more recent versions
of the XML schema.
</p></div><div class="sect2"><div class="titlepage"><div><div><h3 class="title"><a name="launching-batch-jobs-through-messages" href="#launching-batch-jobs-through-messages"></a>13.1.2.&nbsp;Launching Batch Jobs through Messages</h3></div></div></div><p>
When starting batch jobs using the core Spring Batch API you
basically have 2 options:
</p><div class="itemizedlist"><ul class="itemizedlist" style="list-style-type: disc; "><li class="listitem"><p>
Command line via the <code class="classname">CommandLineJobRunner</code>
</p></li><li class="listitem"><p>
Programatically via either
<code class="classname">JobOperator.start()</code> or
<code class="classname">JobLauncher.run()</code>.
</p></li></ul></div><p>
For example, you may want to use the
<code class="classname">CommandLineJobRunner</code> when invoking Batch Jobs
using a shell script. Alternatively, you may use the
<code class="classname">JobOperator</code> directly, for example when using
Spring Batch as part of a web application. However, what about
more complex use-cases? Maybe you need to poll a remote (S)FTP
server to retrieve the data for the Batch Job. Or your application
has to support multiple different data sources simultaneously. For
example, you may receive data files not only via the web, but also
FTP etc. Maybe additional transformation of the input files is
needed before invoking Spring Batch.
</p><p>
Therefore, it would be much more powerful to execute the batch job
using Spring Integration and its numerous adapters. For example,
you can use a <span class="emphasis"><em>File Inbound Channel Adapter</em></span> to
monitor a directory in the file-system and start the Batch Job as
soon as the input file arrives. Additionally you can create Spring
Integration flows that use multiple different adapters to easily
ingest data for your Batch Jobs from multiple sources
simultaneously using configuration only. Implementing all these
scenarios with Spring Integration is easy as it allow for an
decoupled event-driven execution of the
<code class="classname">JobLauncher</code>.
</p><p>
Spring Batch Integration provides the
<code class="classname">JobLaunchingMessageHandler</code> class that you can
use to launch batch jobs. The input for the
<code class="classname">JobLaunchingMessageHandler</code> is provided by a
Spring Integration message, which payload is of type
<code class="classname">JobLaunchRequest</code>. This class is a wrapper around the Job
that needs to be launched as well as the <code class="classname">JobParameters</code>
necessary to launch the Batch job.
</p><p>
The following image illustrates the typical Spring Integration
message flow in order to start a Batch job. The
<a class="ulink" href="http://www.eaipatterns.com/toc.html" target="_top">EIP (Enterprise IntegrationPatterns) website</a>
provides a full overview of messaging icons and their descriptions.
</p><div class="mediaobject" align="center"><img src="images/launch-batch-job.png" align="middle"></div><div class="sect3"><div class="titlepage"><div><div><h4 class="title"><a name="transforming-a-file-into-a-joblaunchrequest" href="#transforming-a-file-into-a-joblaunchrequest"></a>Transforming a file into a JobLaunchRequest</h4></div></div></div><pre class="programlisting"><span class="hl-keyword">package</span> io.spring.sbi;
<span class="hl-keyword">import</span> org.springframework.batch.core.Job;
<span class="hl-keyword">import</span> org.springframework.batch.core.JobParametersBuilder;
<span class="hl-keyword">import</span> org.springframework.batch.integration.launch.JobLaunchRequest;
<span class="hl-keyword">import</span> org.springframework.integration.annotation.Transformer;
<span class="hl-keyword">import</span> org.springframework.messaging.Message;
<span class="hl-keyword">import</span> java.io.File;
<span class="hl-keyword">public</span> <span class="hl-keyword">class</span> FileMessageToJobRequest {
<span class="hl-keyword">private</span> Job job;
<span class="hl-keyword">private</span> String fileParameterName;
<span class="hl-keyword">public</span> <span class="hl-keyword">void</span> setFileParameterName(String fileParameterName) {
<span class="hl-keyword">this</span>.fileParameterName = fileParameterName;
}
<span class="hl-keyword">public</span> <span class="hl-keyword">void</span> setJob(Job job) {
<span class="hl-keyword">this</span>.job = job;
}
<em><span class="hl-annotation" style="color: gray">@Transformer</span></em>
<span class="hl-keyword">public</span> JobLaunchRequest toRequest(Message&lt;File&gt; message) {
JobParametersBuilder jobParametersBuilder =
<span class="hl-keyword">new</span> JobParametersBuilder();
jobParametersBuilder.addString(fileParameterName,
message.getPayload().getAbsolutePath());
<span class="hl-keyword">return</span> <span class="hl-keyword">new</span> JobLaunchRequest(job, jobParametersBuilder.toJobParameters());
}
}</pre></div><div class="sect3"><div class="titlepage"><div><div><h4 class="title"><a name="the-jobexecution-response" href="#the-jobexecution-response"></a>The JobExecution Response</h4></div></div></div><p>
When a Batch Job is being executed, a
<code class="classname">JobExecution</code> instance is returned. This
instance can be used to determine the status of an execution. If
a <code class="classname">JobExecution</code> was able to be created
successfully, it will always be returned, regardless of whether
or not the actual execution was successful.
</p><p>
The exact behavior on how the <code class="classname">JobExecution</code>
instance is returned depends on the provided
<code class="classname">TaskExecutor</code>. If a
<code class="classname">synchronous</code> (single-threaded)
<code class="classname">TaskExecutor</code> implementation is used, the
<code class="classname">JobExecution</code> response is only returned
<code class="classname">after</code> the job completes. When using an
<code class="classname">asynchronous</code>
<code class="classname">TaskExecutor</code>, the
<code class="classname">JobExecution</code> instance is returned
immediately. Users can then take the <code class="classname">id</code> of
<code class="classname">JobExecution</code> instance
(<code class="classname">JobExecution.getJobId()</code>) and query the
<code class="classname">JobRepository</code> for the job's updated status
using the <code class="classname">JobExplorer</code>. For more
information, please refer to the <code class="classname">Spring
Batch</code> reference documentation on
<a class="ulink" href="http://docs.spring.io/spring-batch/reference/html/configureJob.html#queryingRepository" target="_top">Querying
the Repository</a>.
</p><p>
The following configuration will create a file
<code class="classname">inbound-channel-adapter</code> to listen for CSV
files in the provided directory, hand them off to our
transformer (<code class="classname">FileMessageToJobRequest</code>),
launch the job via the <span class="emphasis"><em>Job Launching
Gateway</em></span> then simply log the output of the
<code class="classname">JobExecution</code> via the
<code class="classname">logging-channel-adapter</code>.
</p></div><div class="sect3"><div class="titlepage"><div><div><h4 class="title"><a name="spring-batch-integration-configuration" href="#spring-batch-integration-configuration"></a>Spring Batch Integration Configuration</h4></div></div></div><pre class="programlisting"><span class="hl-tag">&lt;int:channel</span> <span class="hl-attribute">id</span>=<span class="hl-value">"inboundFileChannel"</span><span class="hl-tag">/&gt;</span>
<span class="hl-tag">&lt;int:channel</span> <span class="hl-attribute">id</span>=<span class="hl-value">"outboundJobRequestChannel"</span><span class="hl-tag">/&gt;</span>
<span class="hl-tag">&lt;int:channel</span> <span class="hl-attribute">id</span>=<span class="hl-value">"jobLaunchReplyChannel"</span><span class="hl-tag">/&gt;</span>
<span class="hl-tag">&lt;int-file:inbound-channel-adapter</span> <span class="hl-attribute">id</span>=<span class="hl-value">"filePoller"</span>
<span class="hl-attribute">channel</span>=<span class="hl-value">"inboundFileChannel"</span>
<span class="hl-attribute">directory</span>=<span class="hl-value">"file:/tmp/myfiles/"</span>
<span class="hl-attribute">filename-pattern</span>=<span class="hl-value">"*.csv"</span><span class="hl-tag">&gt;</span>
<span class="hl-tag">&lt;int:poller</span> <span class="hl-attribute">fixed-rate</span>=<span class="hl-value">"1000"</span><span class="hl-tag">/&gt;</span>
<span class="hl-tag">&lt;/int-file:inbound-channel-adapter&gt;</span>
<span class="hl-tag">&lt;int:transformer</span> <span class="hl-attribute">input-channel</span>=<span class="hl-value">"inboundFileChannel"</span>
<span class="hl-attribute">output-channel</span>=<span class="hl-value">"outboundJobRequestChannel"</span><span class="hl-tag">&gt;</span>
<span class="hl-tag">&lt;bean</span> <span class="hl-attribute">class</span>=<span class="hl-value">"io.spring.sbi.FileMessageToJobRequest"</span><span class="hl-tag">&gt;</span>
<span class="hl-tag">&lt;property</span> <span class="hl-attribute">name</span>=<span class="hl-value">"job"</span> <span class="hl-attribute">ref</span>=<span class="hl-value">"personJob"</span><span class="hl-tag">/&gt;</span>
<span class="hl-tag">&lt;property</span> <span class="hl-attribute">name</span>=<span class="hl-value">"fileParameterName"</span> <span class="hl-attribute">value</span>=<span class="hl-value">"input.file.name"</span><span class="hl-tag">/&gt;</span>
<span class="hl-tag">&lt;/bean&gt;</span>
<span class="hl-tag">&lt;/int:transformer&gt;</span>
<span class="hl-tag">&lt;batch-int:job-launching-gateway</span> <span class="hl-attribute">request-channel</span>=<span class="hl-value">"outboundJobRequestChannel"</span>
<span class="hl-attribute">reply-channel</span>=<span class="hl-value">"jobLaunchReplyChannel"</span><span class="hl-tag">/&gt;</span>
<span class="hl-tag">&lt;int:logging-channel-adapter</span> <span class="hl-attribute">channel</span>=<span class="hl-value">"jobLaunchReplyChannel"</span><span class="hl-tag">/&gt;</span></pre><p>
Now that we are polling for files and launching jobs, we need to
configure for example our Spring Batch
<code class="classname">ItemReader</code> to utilize found file
represented by the job parameter "input.file.name":
</p></div><div class="sect3"><div class="titlepage"><div><div><h4 class="title"><a name="example-itemreader-configuration" href="#example-itemreader-configuration"></a>Example ItemReader Configuration</h4></div></div></div><pre class="programlisting"><span class="hl-tag">&lt;bean</span> <span class="hl-attribute">id</span>=<span class="hl-value">"itemReader"</span> <span class="hl-attribute">class</span>=<span class="hl-value">"org.springframework.batch.item.file.FlatFileItemReader"</span>
<span class="hl-attribute">scope</span>=<span class="hl-value">"step"</span><span class="hl-tag">&gt;</span>
<span class="hl-tag">&lt;property</span> <span class="hl-attribute">name</span>=<span class="hl-value">"resource"</span> <span class="hl-attribute">value</span>=<span class="hl-value">"file://#{jobParameters['input.file.name']}"</span><span class="hl-tag">/&gt;</span>
...
<span class="hl-tag">&lt;/bean&gt;</span></pre><p>
The main points of interest here are injecting the value of
<code class="classname">#{jobParameters['input.file.name']}</code>
as the Resource property value and setting the ItemReader bean
to be of <span class="emphasis"><em>Step scope</em></span> to take advantage of
the late binding support which allows access to the
<code class="classname">jobParameters</code> variable.
</p><div class="sect4"><div class="titlepage"><div><div><h5 class="title"><a name="available-attributes-of-the-job-launching-gateway" href="#available-attributes-of-the-job-launching-gateway"></a>Available Attributes of the Job-Launching Gateway</h5></div></div></div><div class="itemizedlist"><ul class="itemizedlist" style="list-style-type: disc; "><li class="listitem"><p>
<code class="classname">id</code> Identifies the
underlying Spring bean definition, which is an instance of
either:
</p><div class="itemizedlist"><ul class="itemizedlist" style="list-style-type: circle; "><li class="listitem"><p>
<code class="classname">EventDrivenConsumer</code>
</p></li><li class="listitem"><p>
<code class="classname">PollingConsumer</code>
</p></li></ul></div><p>
The exact implementation depends on whether the component's
input channel is a:
</p><div class="itemizedlist"><ul class="itemizedlist" style="list-style-type: circle; "><li class="listitem"><p>
<code class="classname">SubscribableChannel</code> or
</p></li><li class="listitem"><p>
<code class="classname">PollableChannel</code>
</p></li></ul></div></li></ul></div><div class="itemizedlist"><ul class="itemizedlist" style="list-style-type: disc; "><li class="listitem"><p>
<code class="classname">auto-startup</code>
Boolean flag to indicate that the endpoint should start automatically on
startup. The default is <span class="emphasis"><em>true</em></span>.
</p></li><li class="listitem"><p>
<code class="classname">request-channel</code>
The input <code class="classname">MessageChannel</code> of this endpoint.
</p></li><li class="listitem"><p>
<code class="classname">reply-channel</code> <code class="classname">Message Channel</code>
to which the resulting <code class="classname">JobExecution</code> payload will be sent.
</p></li><li class="listitem"><p>
<code class="classname">reply-timeout</code>
Allows you to specify how long this gateway will wait for the reply message
to be sent successfully to the reply channel before throwing
an exception. This attribute only applies when the channel
might block, for example when using a bounded queue channel
that is currently full. Also, keep in mind that when sending to a
<code class="classname">DirectChannel</code>, the invocation will occur
in the sender's thread. Therefore, the failing of the send
operation may be caused by other components further downstream.
The <code class="classname">reply-timeout</code> attribute maps to the
<code class="classname">sendTimeout</code> property of the underlying
<code class="classname">MessagingTemplate</code> instance. The attribute
will default, if not specified, to<span class="emphasis"><em>-1</em></span>,
meaning that by default, the Gateway will wait indefinitely.
The value is specified in milliseconds.
</p></li><li class="listitem"><p>
<code class="classname">job-launcher</code>
Pass in a
custom
<code class="classname">JobLauncher</code>
bean reference. This
attribute is optional. If not specified the adapter will
re-use the instance that is registered under the id
<code class="classname">jobLauncher</code>. If no default instance
exists an exception is thrown.
</p></li><li class="listitem"><p>
<code class="classname">order</code>
Specifies the order
for invocation when this endpoint is connected as a subscriber
to a <code class="classname">SubscribableChannel</code>.
</p></li></ul></div></div><div class="sect4"><div class="titlepage"><div><div><h5 class="title"><a name="sub-elements" href="#sub-elements"></a>Sub-Elements</h5></div></div></div><p>
When this Gateway is receiving messages from a
<code class="classname">PollableChannel</code>, you must either provide
a global default Poller or provide a Poller sub-element to the
<code class="classname">Job Launching Gateway</code>:
</p><pre class="programlisting"><span class="hl-tag">&lt;batch-int:job-launching-gateway</span> <span class="hl-attribute">request-channel</span>=<span class="hl-value">"queueChannel"</span>
<span class="hl-attribute">reply-channel</span>=<span class="hl-value">"replyChannel"</span> <span class="hl-attribute">job-launcher</span>=<span class="hl-value">"jobLauncher"</span><span class="hl-tag">&gt;</span>
<span class="hl-tag">&lt;int:poller</span> <span class="hl-attribute">fixed-rate</span>=<span class="hl-value">"1000"</span><span class="hl-tag">/&gt;</span>
<span class="hl-tag">&lt;/batch-int:job-launching-gateway&gt;</span></pre></div></div></div><div class="sect2"><div class="titlepage"><div><div><h3 class="title"><a name="providing-feedback-with-informational-messages" href="#providing-feedback-with-informational-messages"></a>13.1.3.&nbsp;Providing Feedback with Informational Messages</h3></div></div></div><p>
As Spring Batch jobs can run for long times, providing progress
information will be critical. For example, stake-holders may want
to be notified if a some or all parts of a Batch Job has failed.
Spring Batch provides support for this information being gathered
through:
</p><div class="itemizedlist"><ul class="itemizedlist" style="list-style-type: disc; "><li class="listitem"><p>
Active polling or
</p></li><li class="listitem"><p>
Event-driven, using listeners.
</p></li></ul></div><p>
When starting a Spring Batch job asynchronously, e.g. by using the
<code class="classname">Job Launching Gateway</code>, a
<code class="classname">JobExecution</code> instance is returned. Thus,
<code class="classname">JobExecution.getJobId()</code> can be used to
continuously poll for status updates by retrieving updated
instances of the <code class="classname">JobExecution</code> from the
<code class="classname">JobRepository</code> using the
<code class="classname">JobExplorer</code>. However, this is considered
sub-optimal and an event-driven approach should be preferred.
</p><p>
Therefore, Spring Batch provides listeners such as:
</p><div class="itemizedlist"><ul class="itemizedlist" style="list-style-type: disc; "><li class="listitem"><p>
StepListener
</p></li><li class="listitem"><p>
ChunkListener
</p></li><li class="listitem"><p>
JobExecutionListener
</p></li></ul></div><p>
In the following example, a Spring Batch job was configured with a
<code class="classname">StepExecutionListener</code>. Thus, Spring
Integration will receive and process any step before/after step
events. For example, the received
<code class="classname">StepExecution</code> can be inspected using a
<code class="classname">Router</code>. Based on the results of that
inspection, various things can occur for example routing a message
to a Mail Outbound Channel Adapter, so that an Email notification
can be sent out based on some condition.
</p><div class="mediaobject" align="center"><img src="images/handling-informational-messages.png" align="middle"></div><p>
Below is an example of how a listener is configured to send a
message to a <code class="classname">Gateway</code> for
<code class="classname">StepExecution</code> events and log its output to a
<code class="classname">logging-channel-adapter</code>:
</p><p>
First create the notifications integration beans:
</p><pre class="programlisting"><span class="hl-tag">&lt;int:channel</span> <span class="hl-attribute">id</span>=<span class="hl-value">"stepExecutionsChannel"</span><span class="hl-tag">/&gt;</span>
<span class="hl-tag">&lt;int:gateway</span> <span class="hl-attribute">id</span>=<span class="hl-value">"notificationExecutionsListener"</span>
<span class="hl-attribute">service-interface</span>=<span class="hl-value">"org.springframework.batch.core.StepExecutionListener"</span>
<span class="hl-attribute">default-request-channel</span>=<span class="hl-value">"stepExecutionsChannel"</span><span class="hl-tag">/&gt;</span>
<span class="hl-tag">&lt;int:logging-channel-adapter</span> <span class="hl-attribute">channel</span>=<span class="hl-value">"stepExecutionsChannel"</span><span class="hl-tag">/&gt;</span></pre><p>
Then modify your job to add a step level listener:
</p><pre class="programlisting"><span class="hl-tag">&lt;job</span> <span class="hl-attribute">id</span>=<span class="hl-value">"importPayments"</span><span class="hl-tag">&gt;</span>
<span class="hl-tag">&lt;step</span> <span class="hl-attribute">id</span>=<span class="hl-value">"step1"</span><span class="hl-tag">&gt;</span>
<span class="hl-tag">&lt;tasklet</span> <span class="hl-attribute">../&gt;</span>
<span class="hl-attribute">&lt;chunk</span> <span class="hl-attribute">../&gt;</span>
<span class="hl-attribute">&lt;listeners&gt;</span>
<span class="hl-attribute">&lt;listener</span> <span class="hl-attribute">ref</span>=<span class="hl-value">"notificationExecutionsListener"</span><span class="hl-tag">/&gt;</span>
<span class="hl-tag">&lt;/listeners&gt;</span>
<span class="hl-tag">&lt;/tasklet&gt;</span>
...
<span class="hl-tag">&lt;/step&gt;</span>
<span class="hl-tag">&lt;/job&gt;</span></pre></div><div class="sect2"><div class="titlepage"><div><div><h3 class="title"><a name="asynchronous-processors" href="#asynchronous-processors"></a>13.1.4.&nbsp;Asynchronous Processors</h3></div></div></div><p>
Asynchronous Processors help you to to scale the processing of
items. In the asynchronous processor use-case, an
<code class="classname">AsyncItemProcessor</code> serves as a dispatcher,
executing the <code class="classname">ItemProcessor</code>'s logic for an
item on a new thread. The <code class="classname">Future</code> is passed to
the <code class="classname">AsynchItemWriter</code> to be written once the
processor completes.
</p><p>
Therefore, you can increase performance by using asynchronous item
processing, basically allowing you to implement
<span class="emphasis"><em>fork-join</em></span> scenarios. The
<code class="classname">AsyncItemWriter</code> will gather the results and
write back the chunk as soon as all the results become available.
</p><p>
Configuration of both the <code class="classname">AsyncItemProcessor</code>
and <code class="classname">AsyncItemWriter</code> are simple, first the
<code class="classname">AsyncItemProcessor</code>:
</p><pre class="programlisting"><span class="hl-tag">&lt;bean</span> <span class="hl-attribute">id</span>=<span class="hl-value">"processor"</span>
<span class="hl-attribute">class</span>=<span class="hl-value">"org.springframework.batch.integration.async.AsyncItemProcessor"</span><span class="hl-tag">&gt;</span>
<span class="hl-tag">&lt;property</span> <span class="hl-attribute">name</span>=<span class="hl-value">"delegate"</span><span class="hl-tag">&gt;</span>
<span class="hl-tag">&lt;bean</span> <span class="hl-attribute">class</span>=<span class="hl-value">"your.ItemProcessor"</span><span class="hl-tag">/&gt;</span>
<span class="hl-tag">&lt;/property&gt;</span>
<span class="hl-tag">&lt;property</span> <span class="hl-attribute">name</span>=<span class="hl-value">"taskExecutor"</span><span class="hl-tag">&gt;</span>
<span class="hl-tag">&lt;bean</span> <span class="hl-attribute">class</span>=<span class="hl-value">"org.springframework.core.task.SimpleAsyncTaskExecutor"</span><span class="hl-tag">/&gt;</span>
<span class="hl-tag">&lt;/property&gt;</span>
<span class="hl-tag">&lt;/bean&gt;</span></pre><p>
The property "<code class="classname">delegate</code>" is actually
a reference to your <code class="classname">ItemProcessor</code> bean and
the "<code class="classname">taskExecutor</code>" property is a
reference to the <code class="classname">TaskExecutor</code> of your choice.
</p><p>
Then we configure the <code class="classname">AsyncItemWriter</code>:
</p><pre class="programlisting"><span class="hl-tag">&lt;bean</span> <span class="hl-attribute">id</span>=<span class="hl-value">"itemWriter"</span>
<span class="hl-attribute">class</span>=<span class="hl-value">"org.springframework.batch.integration.async.AsyncItemWriter"</span><span class="hl-tag">&gt;</span>
<span class="hl-tag">&lt;property</span> <span class="hl-attribute">name</span>=<span class="hl-value">"delegate"</span><span class="hl-tag">&gt;</span>
<span class="hl-tag">&lt;bean</span> <span class="hl-attribute">id</span>=<span class="hl-value">"itemWriter"</span> <span class="hl-attribute">class</span>=<span class="hl-value">"your.ItemWriter"</span><span class="hl-tag">/&gt;</span>
<span class="hl-tag">&lt;/property&gt;</span>
<span class="hl-tag">&lt;/bean&gt;</span></pre><p>
Again, the property "<code class="classname">delegate</code>" is
actually a reference to your <code class="classname">ItemWriter</code> bean.
</p></div><div class="sect2"><div class="titlepage"><div><div><h3 class="title"><a name="externalizing-batch-process-execution" href="#externalizing-batch-process-execution"></a>13.1.5.&nbsp;Externalizing Batch Process Execution</h3></div></div></div><p>
The integration approaches discussed so far suggest use-cases
where Spring Integration wraps Spring Batch like an outer-shell.
However, Spring Batch can also use Spring Integration internally.
Using this approach, Spring Batch users can delegate the
processing of items or even chunks to outside processes. This
allows you to offload complex processing. Spring Batch Integration
provides dedicated support for:
</p><div class="itemizedlist"><ul class="itemizedlist" style="list-style-type: disc; "><li class="listitem"><p>
Remote Chunking
</p></li><li class="listitem"><p>
Remote Partitioning
</p></li></ul></div><div class="sect3"><div class="titlepage"><div><div><h4 class="title"><a name="remote-chunking" href="#remote-chunking"></a>Remote Chunking</h4></div></div></div><div class="mediaobject" align="center"><img src="images/remote-chunking-sbi.png" align="middle"></div><p>
Taking things one step further, one can also externalize the
chunk processing using the
<code class="classname">ChunkMessageChannelItemWriter</code> which is
provided by Spring Batch Integration which will send items out
and collect the result. Once sent, Spring Batch will continue the
process of reading and grouping items, without waiting for the results.
Rather it is the responsibility of the <code class="classname">ChunkMessageChannelItemWriter</code>
to gather the results and integrate them back into the Spring Batch process.
</p><p>
Using Spring Integration you have full
control over the concurrency of your processes, for instance by
using a <code class="classname">QueueChannel</code> instead of a
<code class="classname">DirectChannel</code>. Furthermore, by relying on
Spring Integration's rich collection of Channel Adapters (E.g.
JMS or AMQP), you can distribute chunks of a Batch job to
external systems for processing.
</p><p>
A simple job with a step to be remotely chunked would have a
configuration similar to the following:
</p><pre class="programlisting"><span class="hl-tag">&lt;job</span> <span class="hl-attribute">id</span>=<span class="hl-value">"personJob"</span><span class="hl-tag">&gt;</span>
<span class="hl-tag">&lt;step</span> <span class="hl-attribute">id</span>=<span class="hl-value">"step1"</span><span class="hl-tag">&gt;</span>
<span class="hl-tag">&lt;tasklet&gt;</span>
<span class="hl-tag">&lt;chunk</span> <span class="hl-attribute">reader</span>=<span class="hl-value">"itemReader"</span> <span class="hl-attribute">writer</span>=<span class="hl-value">"itemWriter"</span> <span class="hl-attribute">commit-interval</span>=<span class="hl-value">"200"</span><span class="hl-tag">/&gt;</span>
<span class="hl-tag">&lt;/tasklet&gt;</span>
...
<span class="hl-tag">&lt;/step&gt;</span>
<span class="hl-tag">&lt;/job&gt;</span></pre><p>
The ItemReader reference would point to the bean you would like
to use for reading data on the master. The ItemWriter reference
points to a special ItemWriter
"<code class="classname">ChunkMessageChannelItemWriter</code>"
as described above. The processor (if any) is left off the
master configuration as it is configured on the slave. The
following configuration provides a basic master setup. It's
advised to check any additional component properties such as
throttle limits and so on when implementing your use case.
</p><pre class="programlisting"><span class="hl-tag">&lt;bean</span> <span class="hl-attribute">id</span>=<span class="hl-value">"connectionFactory"</span> <span class="hl-attribute">class</span>=<span class="hl-value">"org.apache.activemq.ActiveMQConnectionFactory"</span><span class="hl-tag">&gt;</span>
<span class="hl-tag">&lt;property</span> <span class="hl-attribute">name</span>=<span class="hl-value">"brokerURL"</span> <span class="hl-attribute">value</span>=<span class="hl-value">"tcp://localhost:61616"</span><span class="hl-tag">/&gt;</span>
<span class="hl-tag">&lt;/bean&gt;</span>
<span class="hl-tag">&lt;int-jms:outbound-channel-adapter</span> <span class="hl-attribute">id</span>=<span class="hl-value">"requests"</span> <span class="hl-attribute">destination-name</span>=<span class="hl-value">"requests"</span><span class="hl-tag">/&gt;</span>
<span class="hl-tag">&lt;bean</span> <span class="hl-attribute">id</span>=<span class="hl-value">"messagingTemplate"</span>
<span class="hl-attribute">class</span>=<span class="hl-value">"org.springframework.integration.core.MessagingTemplate"</span><span class="hl-tag">&gt;</span>
<span class="hl-tag">&lt;property</span> <span class="hl-attribute">name</span>=<span class="hl-value">"defaultChannel"</span> <span class="hl-attribute">ref</span>=<span class="hl-value">"requests"</span><span class="hl-tag">/&gt;</span>
<span class="hl-tag">&lt;property</span> <span class="hl-attribute">name</span>=<span class="hl-value">"receiveTimeout"</span> <span class="hl-attribute">value</span>=<span class="hl-value">"2000"</span><span class="hl-tag">/&gt;</span>
<span class="hl-tag">&lt;/bean&gt;</span>
<span class="hl-tag">&lt;bean</span> <span class="hl-attribute">id</span>=<span class="hl-value">"itemWriter"</span>
<span class="hl-attribute">class</span>=<span class="hl-value">"org.springframework.batch.integration.chunk.ChunkMessageChannelItemWriter"</span>
<span class="hl-attribute">scope</span>=<span class="hl-value">"step"</span><span class="hl-tag">&gt;</span>
<span class="hl-tag">&lt;property</span> <span class="hl-attribute">name</span>=<span class="hl-value">"messagingOperations"</span> <span class="hl-attribute">ref</span>=<span class="hl-value">"messagingTemplate"</span><span class="hl-tag">/&gt;</span>
<span class="hl-tag">&lt;property</span> <span class="hl-attribute">name</span>=<span class="hl-value">"replyChannel"</span> <span class="hl-attribute">ref</span>=<span class="hl-value">"replies"</span><span class="hl-tag">/&gt;</span>
<span class="hl-tag">&lt;/bean&gt;</span>
<span class="hl-tag">&lt;bean</span> <span class="hl-attribute">id</span>=<span class="hl-value">"chunkHandler"</span>
<span class="hl-attribute">class</span>=<span class="hl-value">"org.springframework.batch.integration.chunk.RemoteChunkHandlerFactoryBean"</span><span class="hl-tag">&gt;</span>
<span class="hl-tag">&lt;property</span> <span class="hl-attribute">name</span>=<span class="hl-value">"chunkWriter"</span> <span class="hl-attribute">ref</span>=<span class="hl-value">"itemWriter"</span><span class="hl-tag">/&gt;</span>
<span class="hl-tag">&lt;property</span> <span class="hl-attribute">name</span>=<span class="hl-value">"step"</span> <span class="hl-attribute">ref</span>=<span class="hl-value">"step1"</span><span class="hl-tag">/&gt;</span>
<span class="hl-tag">&lt;/bean&gt;</span>
<span class="hl-tag">&lt;int:channel</span> <span class="hl-attribute">id</span>=<span class="hl-value">"replies"</span><span class="hl-tag">&gt;</span>
<span class="hl-tag">&lt;int:queue/&gt;</span>
<span class="hl-tag">&lt;/int:channel&gt;</span>
<span class="hl-tag">&lt;int-jms:message-driven-channel-adapter</span> <span class="hl-attribute">id</span>=<span class="hl-value">"jmsReplies"</span>
<span class="hl-attribute">destination-name</span>=<span class="hl-value">"replies"</span>
<span class="hl-attribute">channel</span>=<span class="hl-value">"replies"</span><span class="hl-tag">/&gt;</span></pre><p>
This configuration provides us with a number of beans. We
configure our messaging middleware using ActiveMQ and
inbound/outbound JMS adapters provided by Spring Integration. As
shown, our <code class="classname">itemWriter</code> bean which is
referenced by our job step utilizes the
<code class="classname">ChunkMessageChannelItemWriter</code> for writing chunks over the
configured middleware.
</p><p>
Now lets move on to the slave configuration:
</p><pre class="programlisting"><span class="hl-tag">&lt;bean</span> <span class="hl-attribute">id</span>=<span class="hl-value">"connectionFactory"</span> <span class="hl-attribute">class</span>=<span class="hl-value">"org.apache.activemq.ActiveMQConnectionFactory"</span><span class="hl-tag">&gt;</span>
<span class="hl-tag">&lt;property</span> <span class="hl-attribute">name</span>=<span class="hl-value">"brokerURL"</span> <span class="hl-attribute">value</span>=<span class="hl-value">"tcp://localhost:61616"</span><span class="hl-tag">/&gt;</span>
<span class="hl-tag">&lt;/bean&gt;</span>
<span class="hl-tag">&lt;int:channel</span> <span class="hl-attribute">id</span>=<span class="hl-value">"requests"</span><span class="hl-tag">/&gt;</span>
<span class="hl-tag">&lt;int:channel</span> <span class="hl-attribute">id</span>=<span class="hl-value">"replies"</span><span class="hl-tag">/&gt;</span>
<span class="hl-tag">&lt;int-jms:message-driven-channel-adapter</span> <span class="hl-attribute">id</span>=<span class="hl-value">"jmsIn"</span>
<span class="hl-attribute">destination-name</span>=<span class="hl-value">"requests"</span>
<span class="hl-attribute">channel</span>=<span class="hl-value">"requests"</span><span class="hl-tag">/&gt;</span>
<span class="hl-tag">&lt;int-jms:outbound-channel-adapter</span> <span class="hl-attribute">id</span>=<span class="hl-value">"outgoingReplies"</span>
<span class="hl-attribute">destination-name</span>=<span class="hl-value">"replies"</span>
<span class="hl-attribute">channel</span>=<span class="hl-value">"replies"</span><span class="hl-tag">&gt;</span>
<span class="hl-tag">&lt;/int-jms:outbound-channel-adapter&gt;</span>
<span class="hl-tag">&lt;int:service-activator</span> <span class="hl-attribute">id</span>=<span class="hl-value">"serviceActivator"</span>
<span class="hl-attribute">input-channel</span>=<span class="hl-value">"requests"</span>
<span class="hl-attribute">output-channel</span>=<span class="hl-value">"replies"</span>
<span class="hl-attribute">ref</span>=<span class="hl-value">"chunkProcessorChunkHandler"</span>
<span class="hl-attribute">method</span>=<span class="hl-value">"handleChunk"</span><span class="hl-tag">/&gt;</span>
<span class="hl-tag">&lt;bean</span> <span class="hl-attribute">id</span>=<span class="hl-value">"chunkProcessorChunkHandler"</span>
<span class="hl-attribute">class</span>=<span class="hl-value">"org.springframework.batch.integration.chunk.ChunkProcessorChunkHandler"</span><span class="hl-tag">&gt;</span>
<span class="hl-tag">&lt;property</span> <span class="hl-attribute">name</span>=<span class="hl-value">"chunkProcessor"</span><span class="hl-tag">&gt;</span>
<span class="hl-tag">&lt;bean</span> <span class="hl-attribute">class</span>=<span class="hl-value">"org.springframework.batch.core.step.item.SimpleChunkProcessor"</span><span class="hl-tag">&gt;</span>
<span class="hl-tag">&lt;property</span> <span class="hl-attribute">name</span>=<span class="hl-value">"itemWriter"</span><span class="hl-tag">&gt;</span>
<span class="hl-tag">&lt;bean</span> <span class="hl-attribute">class</span>=<span class="hl-value">"io.spring.sbi.PersonItemWriter"</span><span class="hl-tag">/&gt;</span>
<span class="hl-tag">&lt;/property&gt;</span>
<span class="hl-tag">&lt;property</span> <span class="hl-attribute">name</span>=<span class="hl-value">"itemProcessor"</span><span class="hl-tag">&gt;</span>
<span class="hl-tag">&lt;bean</span> <span class="hl-attribute">class</span>=<span class="hl-value">"io.spring.sbi.PersonItemProcessor"</span><span class="hl-tag">/&gt;</span>
<span class="hl-tag">&lt;/property&gt;</span>
<span class="hl-tag">&lt;/bean&gt;</span>
<span class="hl-tag">&lt;/property&gt;</span>
<span class="hl-tag">&lt;/bean&gt;</span></pre><p>
Most of these configuration items should look familiar from the
master configuration. Slaves do not need access to things like
the Spring Batch <code class="classname">JobRepository</code> nor access
to the actual job configuration file. The main bean of interest
is the
"<code class="classname">chunkProcessorChunkHandler</code>". The
<code class="classname">chunkProcessor</code> property of
<code class="classname">ChunkProcessorChunkHandler</code> takes a
configured <code class="classname">SimpleChunkProcessor</code> which is
where you would provide a reference to your
<code class="classname">ItemWriter</code> and optionally your
<code class="classname">ItemProcessor</code> that will run on the slave
when it receives chunks from the master.
</p><p>
For more information, please also consult the Spring Batch
manual, specifically the chapter on
<a class="ulink" href="http://docs.spring.io/spring-batch/reference/html/scalability.html#remoteChunking" target="_top">Remote
Chunking</a>.
</p></div><div class="sect3"><div class="titlepage"><div><div><h4 class="title"><a name="remote-partitioning" href="#remote-partitioning"></a>Remote Partitioning</h4></div></div></div><div class="mediaobject" align="center"><img src="images/remote-partitioning.png" align="middle"></div><p>
Remote Partitioning, on the other hand, is useful when the
problem is not the processing of items, but the associated I/O
represents the bottleneck. Using Remote Partitioning, work can
be farmed out to slaves that execute complete Spring Batch
steps. Thus, each slave has its own
<code class="classname">ItemReader</code>,
<code class="classname">ItemProcessor</code> and
<code class="classname">ItemWriter</code>. For this purpose, Spring Batch
Integration provides the
<code class="classname">MessageChannelPartitionHandler</code>.
</p><p>
This implementation of the <code class="classname">PartitionHandler</code>
interface uses <code class="classname">MessageChannel</code> instances to
send instructions to remote workers and receive their responses.
This provides a nice abstraction from the transports (E.g. JMS
or AMQP) being used to communicate with the remote workers.
</p><p>
The reference manual section
<a class="ulink" href="http://docs.spring.io/spring-batch/reference/html/scalability.html#partitioning" target="_top">Remote
Partitioning</a> provides an overview of the concepts and
components needed to configure Remote Partitioning and shows an
example of using the default
<code class="classname">TaskExecutorPartitionHandler</code> to partition
in separate local threads of execution. For Remote Partitioning
to multiple JVM's, two additional components are required:
</p><div class="itemizedlist"><ul class="itemizedlist" style="list-style-type: disc; "><li class="listitem"><p>
Remoting fabric or grid environment
</p></li><li class="listitem"><p>
A PartitionHandler implementation that supports the desired
remoting fabric or grid environment
</p></li></ul></div><p>
Similar to Remote Chunking JMS can be used as the "remoting
fabric" and the PartitionHandler implementation to be used
as described above is the
<code class="classname">MessageChannelPartitionHandler</code>. The example
shown below assumes an existing partitioned job and focuses on
the <code class="classname">MessageChannelPartitionHandler</code> and JMS
configuration:
</p><pre class="programlisting"><span class="hl-tag">&lt;bean</span> <span class="hl-attribute">id</span>=<span class="hl-value">"partitionHandler"</span>
<span class="hl-attribute">class</span>=<span class="hl-value">"org.springframework.batch.integration.partition.MessageChannelPartitionHandler"</span><span class="hl-tag">&gt;</span>
<span class="hl-tag">&lt;property</span> <span class="hl-attribute">name</span>=<span class="hl-value">"stepName"</span> <span class="hl-attribute">value</span>=<span class="hl-value">"step1"</span><span class="hl-tag">/&gt;</span>
<span class="hl-tag">&lt;property</span> <span class="hl-attribute">name</span>=<span class="hl-value">"gridSize"</span> <span class="hl-attribute">value</span>=<span class="hl-value">"3"</span><span class="hl-tag">/&gt;</span>
<span class="hl-tag">&lt;property</span> <span class="hl-attribute">name</span>=<span class="hl-value">"replyChannel"</span> <span class="hl-attribute">ref</span>=<span class="hl-value">"outbound-replies"</span><span class="hl-tag">/&gt;</span>
<span class="hl-tag">&lt;property</span> <span class="hl-attribute">name</span>=<span class="hl-value">"messagingOperations"</span><span class="hl-tag">&gt;</span>
<span class="hl-tag">&lt;bean</span> <span class="hl-attribute">class</span>=<span class="hl-value">"org.springframework.integration.core.MessagingTemplate"</span><span class="hl-tag">&gt;</span>
<span class="hl-tag">&lt;property</span> <span class="hl-attribute">name</span>=<span class="hl-value">"defaultChannel"</span> <span class="hl-attribute">ref</span>=<span class="hl-value">"outbound-requests"</span><span class="hl-tag">/&gt;</span>
<span class="hl-tag">&lt;property</span> <span class="hl-attribute">name</span>=<span class="hl-value">"receiveTimeout"</span> <span class="hl-attribute">value</span>=<span class="hl-value">"100000"</span><span class="hl-tag">/&gt;</span>
<span class="hl-tag">&lt;/bean&gt;</span>
<span class="hl-tag">&lt;/property&gt;</span>
<span class="hl-tag">&lt;/bean&gt;</span>
<span class="hl-tag">&lt;int:channel</span> <span class="hl-attribute">id</span>=<span class="hl-value">"outbound-requests"</span><span class="hl-tag">/&gt;</span>
<span class="hl-tag">&lt;int-jms:outbound-channel-adapter</span> <span class="hl-attribute">destination</span>=<span class="hl-value">"requestsQueue"</span>
<span class="hl-attribute">channel</span>=<span class="hl-value">"outbound-requests"</span><span class="hl-tag">/&gt;</span>
<span class="hl-tag">&lt;int:channel</span> <span class="hl-attribute">id</span>=<span class="hl-value">"inbound-requests"</span><span class="hl-tag">/&gt;</span>
<span class="hl-tag">&lt;int-jms:message-driven-channel-adapter</span> <span class="hl-attribute">destination</span>=<span class="hl-value">"requestsQueue"</span>
<span class="hl-attribute">channel</span>=<span class="hl-value">"inbound-requests"</span><span class="hl-tag">/&gt;</span>
<span class="hl-tag">&lt;bean</span> <span class="hl-attribute">id</span>=<span class="hl-value">"stepExecutionRequestHandler"</span>
<span class="hl-attribute">class</span>=<span class="hl-value">"org.springframework.batch.integration.partition.StepExecutionRequestHandler"</span><span class="hl-tag">&gt;</span>
<span class="hl-tag">&lt;property</span> <span class="hl-attribute">name</span>=<span class="hl-value">"jobExplorer"</span> <span class="hl-attribute">ref</span>=<span class="hl-value">"jobExplorer"</span><span class="hl-tag">/&gt;</span>
<span class="hl-tag">&lt;property</span> <span class="hl-attribute">name</span>=<span class="hl-value">"stepLocator"</span> <span class="hl-attribute">ref</span>=<span class="hl-value">"stepLocator"</span><span class="hl-tag">/&gt;</span>
<span class="hl-tag">&lt;/bean&gt;</span>
<span class="hl-tag">&lt;int:service-activator</span> <span class="hl-attribute">ref</span>=<span class="hl-value">"stepExecutionRequestHandler"</span> <span class="hl-attribute">input-channel</span>=<span class="hl-value">"inbound-requests"</span>
<span class="hl-attribute">output-channel</span>=<span class="hl-value">"outbound-staging"</span><span class="hl-tag">/&gt;</span>
<span class="hl-tag">&lt;int:channel</span> <span class="hl-attribute">id</span>=<span class="hl-value">"outbound-staging"</span><span class="hl-tag">/&gt;</span>
<span class="hl-tag">&lt;int-jms:outbound-channel-adapter</span> <span class="hl-attribute">destination</span>=<span class="hl-value">"stagingQueue"</span>
<span class="hl-attribute">channel</span>=<span class="hl-value">"outbound-staging"</span><span class="hl-tag">/&gt;</span>
<span class="hl-tag">&lt;int:channel</span> <span class="hl-attribute">id</span>=<span class="hl-value">"inbound-staging"</span><span class="hl-tag">/&gt;</span>
<span class="hl-tag">&lt;int-jms:message-driven-channel-adapter</span> <span class="hl-attribute">destination</span>=<span class="hl-value">"stagingQueue"</span>
<span class="hl-attribute">channel</span>=<span class="hl-value">"inbound-staging"</span><span class="hl-tag">/&gt;</span>
<span class="hl-tag">&lt;int:aggregator</span> <span class="hl-attribute">ref</span>=<span class="hl-value">"partitionHandler"</span> <span class="hl-attribute">input-channel</span>=<span class="hl-value">"inbound-staging"</span>
<span class="hl-attribute">output-channel</span>=<span class="hl-value">"outbound-replies"</span><span class="hl-tag">/&gt;</span>
<span class="hl-tag">&lt;int:channel</span> <span class="hl-attribute">id</span>=<span class="hl-value">"outbound-replies"</span><span class="hl-tag">&gt;</span>
<span class="hl-tag">&lt;int:queue/&gt;</span>
<span class="hl-tag">&lt;/int:channel&gt;</span>
<span class="hl-tag">&lt;bean</span> <span class="hl-attribute">id</span>=<span class="hl-value">"stepLocator"</span>
<span class="hl-attribute">class</span>=<span class="hl-value">"org.springframework.batch.integration.partition.BeanFactoryStepLocator"</span><span class="hl-tag"> /&gt;</span></pre><p>
Also ensure the partition <code class="classname">handler</code> attribute
maps to the <code class="classname">partitionHandler</code> bean:
</p><pre class="programlisting"><span class="hl-tag">&lt;job</span> <span class="hl-attribute">id</span>=<span class="hl-value">"personJob"</span><span class="hl-tag">&gt;</span>
<span class="hl-tag">&lt;step</span> <span class="hl-attribute">id</span>=<span class="hl-value">"step1.master"</span><span class="hl-tag">&gt;</span>
<span class="hl-tag">&lt;partition</span> <span class="hl-attribute">partitioner</span>=<span class="hl-value">"partitioner"</span> <span class="hl-attribute">handler</span>=<span class="hl-value">"partitionHandler"</span><span class="hl-tag">/&gt;</span>
...
<span class="hl-tag">&lt;/step&gt;</span>
<span class="hl-tag">&lt;/job&gt;</span></pre></div></div></div></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="jsr-352.html">Prev</a>&nbsp;</td><td width="20%" align="center">&nbsp;</td><td width="40%" align="right">&nbsp;<a accesskey="n" href="listOfReadersAndWriters.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">12.&nbsp;JSR-352 Support&nbsp;</td><td width="20%" align="center"><a accesskey="h" href="index.html">Home</a></td><td width="40%" align="right" valign="top">&nbsp;Appendix&nbsp;A.&nbsp;List of ItemReaders and ItemWriters</td></tr></table></div></body></html>