In the outline for this example job , the first step had to come before the second two because the
second two are dependent on the first. The second two, however, do not share any such dependencies.
There's no reason why the audit log couldn't be written at the same time as the JMS messages are being
delivered. Spring Batch provides the capability to fork processing to enable just this sort of arrangement:
<step id="loadRegistrations" next="finalizeRegistrations" ➥
> <!-- ... --> </step>
<split id="finalizeRegistrations" >
<step id="reportStatistics" ><!-- ... --></step>
<step id="sendJmsNotifications" > <!-- ... --></step>
In this example, there's nothing to prevent you from having many step s within the flow elements,
nor was there anything preventing you from having more step s after the split element. The split
element, like the step elements, takes a next attribute as well.
Spring Batch provides a mechanism to offload processing to another process. This feature, called
remote chunking , is new in Spring Batch 2.0. This distribution requires some sort of durable, reliable
connection. This is a perfect use of JMS because it's rock-solid and transactional, fast, and reliable.
Spring Batch support is modeled at a slightly higher level, on top of the Spring Integration abstractions
for Spring Integration channels. This support is not in the main Spring Batch code, though. Remote
chunking lets individual step s read and aggregate items_as usual_in the main thread. This step is called
the Master . Items read are sent to the ItemProcessor / ItemWriter running in another process (this is
called the Slave ). If the Slave is an aggressive consumer, you have a simple, generic mechanism to scale:
work is instantly farmed out over as many JMS clients as you can throw at it. The aggressive-consumer
pattern refers to the arrangement of multiple JMS clients all consuming the same queue's messages. If
one client consumes a message and is busy processing, other idle queues will get the message instead. As
long as there's a client that's idle, the message will be processed instantly.
Additionally, Spring Batch supports implicitly scaling out using a feature called partitioning . This
feature is interesting because it's built in and generally very flexible. You replace your instance of a step
with a subclass, PartitionStep , which knows how to coordinate distributed executors and maintains the
metadata for the execution of the step , thus eliminating the need for a durable medium of
communication as in the “remote chunking” technology.
The functionality here is also very generic. It could, conceivably, be used with any sort of grid
fabric technology such as GridGain or Hadoop. (For more on GridGain, see Chapter 10.) Spring Batch
ships with only a TaskExecutorPartitionHandler , which executes step s in multiple threads using a
TaskExecutor strategy. This simple improvement might be enough of a justification for this feature! If
you're really hurting, however, you can extend it.
Conditional Steps with Statuses
Using the ExitStatus of a given step to determine the next step is the simplest example of a conditional
flow. Spring Batch facilitates this through the use of the stop , next , fail and end elements. By default,
assuming no intervention, a step will have an ExitStatus that matches its BatchStatus , which is a
property whose values are defined in an enum and may be any of the following: COMPLETED , COMPLETED
WITH SKIPS , STARTING , STARTED , STOPPING , STOPPED , FAILED , ABANDONED or UNKNOWN .