Merge pull request #200 from mminella/BATCH-2056

* BATCH-2056:
  BATCH-2056: Updated documentation
This commit is contained in:
Michael Minella
2013-07-26 10:58:34 -05:00
4 changed files with 211 additions and 415 deletions

View File

@@ -37,7 +37,7 @@ import org.springframework.transaction.PlatformTransactionManager;
* <pre class="code">
* &#064;Configuration
* &#064;EnableBatchProcessing
* &#064;Import(DataSourceCnfiguration.class)
* &#064;Import(DataSourceConfiguration.class)
* public class AppConfig {
*
* &#064;Autowired
@@ -167,4 +167,4 @@ public @interface EnableBatchProcessing {
*/
boolean modular() default false;
}
}

View File

@@ -226,12 +226,101 @@ catch (JobRestartException e) {
</section>
</section>
<section id="javaConfig">
<title>Java Config</title>
<para>Spring 3 brought the ability to configure applications via java instead
of XML. As of Spring Batch 2.2.0, batch jobs can be configured using the same
java config. There are two components for the java based configuration:
the <classname>@EnableBatchConfiguration</classname> annotation and two builders.</para>
<para>The <classname>@EnableBatchProcessing</classname> works similarly to the other
<classname>@Enable*</classname> annotations in the Spring family. In this case,
<classname>@EnableBatchProcessing</classname> provides a base configuration for
building batch jobs. Within this base configuration, an instance of
<classname>StepScope</classname> is createded in addition to a number of beans made
available to be autowired:
</para>
<itemizedlist>
<listitem>
<para><classname>JobRepository</classname> - bean name "jobRepository"</para>
</listitem>
<listitem>
<para><classname>JobLauncher</classname> - bean name "jobLauncher"</para>
</listitem>
<listitem>
<para><classname>JobRegistry</classname> - bean name "jobRegistry"</para>
</listitem>
<listitem>
<para><classname>PlatformTransactionManager</classname> - bean name "transactionManager"</para>
</listitem>
<listitem>
<para><classname>JobBuilderFactory</classname> - bean name "jobBuilders"</para>
</listitem>
<listitem>
<para><classname>StepBuilderFactory</classname> - bean name "stepBuilders"</para>
</listitem>
</itemizedlist>
<para>The core interface for this configuration is the <classname>BatchConfigurer</classname>.
The default implementation provides the beans mentioned above and requires a
<classname>DataSource</classname> as a bean within the context to be provided. This data
source will be used by the <classname>JobRepository</classname>.
</para>
<note>
<para>Only one configuration class needs to have the
<classname>@EnableBatchProcessing</classname> annotation. Once you have a class
annotated with it, you will have all of the above available.</para>
</note>
<para>With the base configuration in place, a user can use the provided builder factories
to configure a job. Below is an example of a two step job configured via the
<classname>JobBuilderFactory</classname> and the <classname>StepBuilderFactory</classname>.</para>
<programlisting>&#064;Configuration
&#064;EnableBatchProcessing
&#064;Import(DataSourceCnfiguration.class)
public class AppConfig {
&#064;Autowired
private JobBuilderFactory jobs;
&#064;Autowired
private StepBuilderFactory steps;
&#064;Bean
public Job job() {
return jobs.get(&quot;myJob&quot;).start(step1()).next(step2()).build();
}
&#064;Bean
protected Step step1(ItemReader&lt;Person&gt; reader, ItemProcessor&lt;Person, Person&gt; processor, ItemWriter&lt;Person&gt; writer) {
return steps.get("step1")
.&lt;Person, Person&gt; chunk(10)
.reader(reader)
.processor(processor)
.writer(writer)
.build();
}
&#064;Bean
protected Step step2(Tasklet tasklet) {
return steps.get("step2")
.tasklet(tasklet)
.build();
}
}</programlisting>
</section>
<section id="configuringJobRepository">
<title>Configuring a JobRepository</title>
<para>As described in earlier, the <link linkend="jobRepository">
<classname>JobRepository</classname>
@@ -246,7 +335,7 @@ catch (JobRestartException e) {
collaborators. However, there are still a few configuration options
available:</para>
<programlisting><![CDATA[<job-repository id="jobRepository"
data-source="dataSource"
@@ -256,7 +345,7 @@ catch (JobRestartException e) {
max-varchar-length="1000"
/>]]></programlisting>
<para>None of the configuration options listed above are required except
the id. If they are not set, the defaults shown above will be used. They
@@ -265,7 +354,7 @@ catch (JobRestartException e) {
length of the long <literal>VARCHAR</literal> columns in the <link
linkend="metaDataSchemaOverview">sample schema scripts</link></para>
used to store things like exit code descriptions. If you don't modify the schema and you don't use multi-byte characters you shouldn't need to change it.
used to store things like exit code descriptions. If you don't modify the schema and you don't use multi-byte characters you shouldn't need to change it.
<section id="txConfigForJobRepository">
<title>Transaction Configuration for the JobRepository</title>
@@ -297,7 +386,7 @@ catch (JobRestartException e) {
<para>
<programlisting><![CDATA[<aop:config>
<aop:advisor
<aop:advisor
pointcut="execution(* org.springframework.batch.core..*Repository+.*(..))"/>
<advice-ref="txAdvice" />
</aop:config>
@@ -315,7 +404,7 @@ catch (JobRestartException e) {
classpath.</para>
</section>
<section id="repositoryTablePrefix">
<title>Changing the Table Prefix</title>
@@ -342,7 +431,7 @@ catch (JobRestartException e) {
</note>
</section>
<section id="inMemoryRepository">
<title>In-Memory Repository</title>
@@ -354,7 +443,7 @@ catch (JobRestartException e) {
this reason, Spring batch provides an in-memory Map version of the job
repository:</para>
<programlisting><![CDATA[<bean id="jobRepository"
<programlisting><![CDATA[<bean id="jobRepository"
class="org.springframework.batch.core.repository.support.MapJobRepositoryFactoryBean">
<property name="transactionManager" ref="transactionManager"/>
</bean>]]></programlisting>
@@ -373,7 +462,7 @@ catch (JobRestartException e) {
<classname>ResourcelessTransactionManager</classname> useful.</para>
</section>
<section id="nonStandardDatabaseTypesInRepository">
<title>Non-standard Database Types in a Repository</title>
@@ -404,7 +493,7 @@ catch (JobRestartException e) {
on and wire one up manually in the normal Spring way.</para>
</section>
</section>
<section id="configuringJobLauncher">
@@ -777,7 +866,7 @@ public class JobLauncherController {
<classname>JobRepository</classname>, it can be easily configured via a
factory bean:</para>
<programlisting><![CDATA[<bean id="jobExplorer" class="org.spr...JobExplorerFactoryBean"
<programlisting><![CDATA[<bean id="jobExplorer" class="org.spr...JobExplorerFactoryBean"
p:dataSource-ref="dataSource" />]]></programlisting>
<para><link linkend="repositoryTablePrefix">Earlier in this
@@ -787,7 +876,7 @@ public class JobLauncherController {
<classname>JobExplorer</classname> is working with the same tables, it
too needs the ability to set a prefix:</para>
<programlisting><![CDATA[<bean id="jobExplorer" class="org.spr...JobExplorerFactoryBean"
<programlisting><![CDATA[<bean id="jobExplorer" class="org.spr...JobExplorerFactoryBean"
p:dataSource-ref="dataSource" ]]><emphasis role="bold">p:tablePrefix="BATCH_" </emphasis><![CDATA[/>]]></programlisting>
</section>
@@ -899,30 +988,30 @@ public class JobLauncherController {
List<Long> getExecutions(long instanceId) throws NoSuchJobInstanceException;
List<Long> getJobInstances(String jobName, int start, int count)
List<Long> getJobInstances(String jobName, int start, int count)
throws NoSuchJobException;
Set<Long> getRunningExecutions(String jobName) throws NoSuchJobException;
String getParameters(long executionId) throws NoSuchJobExecutionException;
Long start(String jobName, String parameters)
Long start(String jobName, String parameters)
throws NoSuchJobException, JobInstanceAlreadyExistsException;
Long restart(long executionId)
Long restart(long executionId)
throws JobInstanceAlreadyCompleteException, NoSuchJobExecutionException,
NoSuchJobException, JobRestartException;
Long startNextInstance(String jobName)
throws NoSuchJobException, JobParametersNotFoundException, JobRestartException,
Long startNextInstance(String jobName)
throws NoSuchJobException, JobParametersNotFoundException, JobRestartException,
JobExecutionAlreadyRunningException, JobInstanceAlreadyCompleteException;
boolean stop(long executionId)
boolean stop(long executionId)
throws NoSuchJobExecutionException, JobExecutionNotRunningException;
String getSummary(long executionId) throws NoSuchJobExecutionException;
Map<Long, String> getStepExecutionSummaries(long executionId)
Map<Long, String> getStepExecutionSummaries(long executionId)
throws NoSuchJobExecutionException;
Set<String> getJobNames();
@@ -996,8 +1085,8 @@ public class JobLauncherController {
as shown below:</para>
<programlisting><![CDATA[public class SampleIncrementer implements JobParametersIncrementer {
public JobParameters getNext(JobParameters parameters) {
public JobParameters getNext(JobParameters parameters) {
if (parameters==null || parameters.isEmpty()) {
return new JobParametersBuilder().addLong("run.id", 1L).toJobParameters();
}

View File

@@ -7,6 +7,11 @@
<section id="retryTemplate">
<title>RetryTemplate</title>
<note>
<para>The retry functionality was pulled out of Spring Batch as of 2.2.0.
It is now part of a new library, Spring Retry.</para>
</note>
<para>To make processing more robust and less prone to failure, sometimes
it helps to automatically retry a failed operation in case it might
succeed on a subsequent attempt. Errors that are susceptible to this kind
@@ -22,13 +27,13 @@
&lt;T&gt; T execute(RetryCallback&lt;T&gt; retryCallback) throws Exception;
&lt;T&gt; T execute(RetryCallback&lt;T&gt; retryCallback, RecoveryCallback&lt;T&gt; recoveryCallback)
&lt;T&gt; T execute(RetryCallback&lt;T&gt; retryCallback, RecoveryCallback&lt;T&gt; recoveryCallback)
throws Exception;
&lt;T&gt; T execute(RetryCallback&lt;T&gt; retryCallback, RetryState retryState)
&lt;T&gt; T execute(RetryCallback&lt;T&gt; retryCallback, RetryState retryState)
throws Exception, ExhaustedRetryException;
&lt;T&gt; T execute(RetryCallback&lt;T&gt; retryCallback, RecoveryCallback&lt;T&gt; recoveryCallback,
&lt;T&gt; T execute(RetryCallback&lt;T&gt; retryCallback, RecoveryCallback&lt;T&gt; recoveryCallback,
RetryState retryState) throws Exception;
}</programlisting>The basic callback is a simple interface that allows you to
@@ -276,7 +281,7 @@ template.execute(new RetryCallback&lt;Foo&gt;() {
BackOffContext start(RetryContext context);
void backOff(BackOffContext backOffContext)
void backOff(BackOffContext backOffContext)
throws BackOffInterruptedException;
}</programlisting>A <classname>BackoffPolicy</classname> is free to implement

View File

@@ -2,427 +2,129 @@
<!DOCTYPE chapter PUBLIC "-//OASIS//DTD DocBook XML V4.4//EN"
"http://www.oasis-open.org/docbook/xml/4.4/docbookx.dtd">
<chapter id="whatsNew">
<title>What's New in Spring Batch 2.0</title>
<title>What's New in Spring Batch 2.2</title>
<para>The Spring Batch 2.0 release has six major themes:</para>
<para>The Spring Batch 2.2 release has six major themes:</para>
<itemizedlist>
<listitem>
<para>Java 5</para>
<para>Spring Data Integration</para>
</listitem>
<listitem>
<para>Non Sequential Step Execution</para>
<para>Java Configuration</para>
</listitem>
<listitem>
<para>Chunk oriented processing</para>
<para>Spring Retry</para>
</listitem>
<listitem>
<para>Meta Data enhancements</para>
</listitem>
<listitem>
<para>Scalability</para>
</listitem>
<listitem>
<para>Configuration</para>
<para>Job Parameters</para>
</listitem>
</itemizedlist>
<section id="whatsNewJava5">
<title id="s.2.1.6">Java 5</title>
<section id="whatsNewSpringData">
<title id="s.2.1.6">Spring Data Integration</title>
<para>The 1.x releases of Spring Batch were all based on Java 1.4. This
prevented the framework from using many enhancements provided in Java 5
such as generics, parameterized types, etc. The entire framework has been
updated to utilize these features. As a result, <emphasis role="bold">Java
1.4 is no longer supported.</emphasis> Most of the interfaces developers
work with have been updated to support generic types. As an example, the
<classname>ItemReader</classname> interface from 1.1 is below:</para>
<para>Since the 2.0 release of Spring Batch, the Spring Data project has brought
support for the NoSQL movement to Spring. The 2.2 release of Spring Batch has added
support for MongoDB, Neo4j and Gemfire natively through the Spring Data abstractions.</para>
<programlisting>public interface ItemReader {
Object read() throws Exception;
void mark() throws MarkFailedException;
void reset() throws ResetFailedException;
}</programlisting>
<para>As you can see, the <methodname>read</methodname> method returns an
<classname>Object</classname>. The 2.0 version is below:</para>
<programlisting>public interface ItemReader&lt;T&gt; {
T read() throws Exception, UnexpectedInputException, ParseException;
}</programlisting>
<para>As you can see, <classname>ItemReader</classname> now supports the
generic type, <classname>T</classname>, which is returned from read. You
may also notice that <methodname>mark</methodname> and
<methodname>reset</methodname> have been removed. This is due to step
processing strategy changes, which are discussed below. Many other
interfaces have been similarly updated.</para>
<para>This release has also added support for writing to any custom Spring Data Repository a
user may write. The <classname>RepositoryItemReader</classname> and
<classname>RepositoryItemWriter</classname> each wrap a repository implementation (
<classname>PagingAndSortingRepository</classname> and <classname>CrudRepository</classname>
respectively) to retrieve data from and persist data to.</para>
</section>
<section id="whatsNewChunkOrientedProcessing">
<title>Chunk Oriented Processing</title>
<section id="whatsNewJavaConfiguration">
<title>Java Configuration</title>
<para>Previously, the default processing strategy provided by Spring Batch
was item-oriented processing:</para>
<para>Until 2.2.0 the only option for configuring a job was via XML (either through the batch DSL or
by hand). However, in 2.2.0, Java based configuration has been added as a way to define Spring Batch
Jobs. To support this new configuration option, an annotation and builder classes have been added. What
was previously defined as this:</para>
<mediaobject>
<imageobject role="html">
<imagedata align="center"
fileref="images/item-oriented-processing.png" scale="80"
width="" />
</imageobject>
<programlisting>&lt;batch&gt;
&lt;job-repository/&gt;
<imageobject role="fo">
<imagedata align="center"
fileref="images/item-oriented-processing.png" scale="60" />
</imageobject>
</mediaobject>
&lt;job id="myJob"&gt;
&lt;step id="step1".../&gt;
&lt;step id="step2".../&gt;
&lt;/job&gt;
<para>In item-oriented processing, the <classname>ItemReader</classname>
returns one <classname>Object</classname> (the 'item') which is then
handed to the <classname>ItemWriter</classname>, periodically committing
when the number of items hits the commit interval. For example, if the
commit interval is 5, <classname>ItemReader</classname> and
<classname>ItemWriter</classname> will each be called 5 times. This is
illustrated in a simplified code example below:</para>
&lt;beans:bean id="transactionManager".../&gt;
<programlisting>for(int i = 0; i &lt; commitInterval; i++){
Object item = itemReader.read();
itemWriter.write(item);
&lt;beans:bean id="jobLauncher" class="org.springframework.batch.core.launch.support.SimpleJobLauncher"&gt;
&lt;beans:property name="jobRepository" ref="jobRepository"/&gt;
&lt;/beans:bean&gt;
&lt;/batch&gt;
</programlisting>
<para>Can now be configured using the <classname>@EnableBatchProcessing</classname> annotation and the
provided <classname>JobBuilderFactory</classname> and <classname>StepBuilderFactory</classname> as show below:</para>
<programlisting> &#064;Configuration
&#064;EnableBatchProcessing
&#064;Import(DataSourceCnfiguration.class)
public class AppConfig {
&#064;Autowired
private JobBuilderFactory jobs;
&#064;Bean
public Job job() {
return jobs.get(&quot;myJob&quot;).start(step1()).next(step2()).build();
}
&#064;Bean
protected Step step1() {
...
}
&#064;Bean
protected Step step2() {
...
}
}</programlisting>
<para>Both the <classname>ItemReader</classname> and
<classname>ItemWriter</classname> interfaces were completely geared toward
this approach:</para>
<programlisting>public interface ItemReader {
Object read() throws Exception;
void mark() throws MarkFailedException;
void reset() throws ResetFailedException;
}</programlisting>
<programlisting>public interface ItemWriter {
void write(Object item) throws Exception;
void flush() throws FlushFailedException;
void clear() throws ClearFailedException;
}</programlisting>
<para>Because the 'scope' of the processing was one item, supporting
rollback scenarios required additional methods, which is what
<methodname>mark</methodname>, <methodname>reset</methodname>,
<methodname>flush</methodname>, and <methodname>clear</methodname>
provided. If, after successfully reading and writing 2 items, the third
has an error while writing, the transaction would need to be rolled back.
In this case, the <methodname>clear</methodname> method on the writer
would be called, indicating that it should <methodname>clear</methodname>
its buffer, and <methodname>reset</methodname> would be called on the
<classname>ItemReader</classname>, indicating that it should return back
to the last position it was at when <methodname>mark</methodname> was
called. (Both <methodname>mark</methodname> and
<methodname>flush</methodname> are called on commit)</para>
<para>In 2.0, this strategy has been changed to a chunk-oriented
approach:</para>
<mediaobject>
<imageobject role="html">
<imagedata align="center"
fileref="images/simplified-chunk-oriented-processing.png"
scale="80" width="" />
</imageobject>
<imageobject role="fo">
<imagedata align="center"
fileref="images/simplified-chunk-oriented-processing.png"
scale="60" />
</imageobject>
</mediaobject>
<para>Using the same example from above, if the commit interval is five,
read will be called 5 times, and write once. The items read will be
aggregated into a list, that will ultimately be written out, as the
simplified example below illustrates:</para>
<programlisting>List items = new Arraylist();
for(int i = 0; i &lt; commitInterval; i++){
items.add(itemReader.read());
}
itemWriter.write(items);</programlisting>
<para>This approach not only allows for much simpler processing and
scalability approaches, it also makes the
<classname>ItemReader</classname> and <classname>ItemWriter</classname>
interfaces much cleaner:</para>
<programlisting>public interface ItemReader&lt;T&gt; {
T read() throws Exception, UnexpectedInputException, ParseException;
}</programlisting>
<programlisting>public interface ItemWriter&lt;T&gt; {
void write(List&lt;? extends T&gt; items) throws Exception;
}</programlisting>
<para>As you can see, the interfaces no longer contain the
<methodname>mark</methodname>, <methodname>reset</methodname>,
<methodname>flush</methodname>, and <methodname>clear</methodname>
methods. This makes the creation of readers and writers much more
straightforward for developers. In the case of
<classname>ItemReader</classname>, the interface is now forward-only. The
framework will buffer read items for developers in the case of rollback
(though there are exceptions if the underlying resource is transactional
see: <xref linkend="transactionalReaders" />).
<classname>ItemWriter</classname> is also simplified, since it gets the
entire 'chunk' of items at once, rather than one at a time, it can decide
to flush any resources (such as a file or hibernate session) before
returning control to the <classname>Step</classname>. More detailed
information on chunk-oriented processing can be found in <xref
linkend="chunkOrientedProcessing" />. Reader and writer implementation
information can be found in <xref linkend="readersAndWriters" />.</para>
<section id="whatsNewItemProcessor">
<title>ItemProcessor</title>
<para>Previously, <classname>Step</classname>s had only two
dependencies, <classname>ItemReader</classname> and
<classname>ItemWriter</classname>:</para>
<mediaobject>
<imageobject role="html">
<imagedata align="center" fileref="images/1-1-step.png" scale="60" />
</imageobject>
<imageobject role="fo">
<imagedata align="center" fileref="images/1-1-step.png" scale="50" />
</imageobject>
</mediaobject>
<para>The basic configuration above is fairly robust. However, there are
many cases where the item needs to be transformed before writing. In 1.x
this can be achieved using the composite pattern:</para>
<mediaobject>
<imageobject role="html">
<imagedata align="center" fileref="images/composite-transformer.png"
scale="95" />
</imageobject>
<imageobject role="fo">
<imagedata align="center" fileref="images/composite-transformer.png"
scale="55" />
</imageobject>
</mediaobject>
<para>This approach works. However, it requires an extra layer between
either the reader or the writer and the <classname>Step</classname>.
Furthermore, the <classname>ItemWriter</classname> would need to be
registered separately as an <classname>ItemStream</classname> with the
<classname>Step</classname>. For this reason, the
<classname>ItemTransfomer</classname> was renamed to
<classname>ItemProcessor</classname> and moved up to the same level as
<classname>ItemReader</classname> and
<classname>ItemWriter</classname>:</para>
<mediaobject>
<imageobject role="html">
<imagedata align="center" fileref="images/step.png" scale="60" />
</imageobject>
<imageobject role="fo">
<imagedata align="center" fileref="images/step.png" scale="50" />
</imageobject>
</mediaobject>
</section>
<para>The <classname>@EnableBatchProcessing</classname> annotation makes a number
of common dependencies available for autowiring by default. This list includes a
<classname>JobRepsitory</classname>, <classname>JobLauncher</classname>,
<classname>JobRegistry</classname>, <classname>PlatformTransactionManager</classname>,
<classname>JobBuilderFactory</classname>, and a <classname>StepBuilderFactory</classname>.
More information on how to configure Jobs and Steps with the new
Java config can be found in <xref linkend="javaConfig" /></para>
</section>
<section id="whatsNewConfiguration">
<title>Configuration Enhancements</title>
<section id="whatsNewSpringRetry">
<title>Spring Retry</title>
<para>Until 2.0, the only option for configuring batch jobs has been
normal spring bean configuration. However, in 2.0 there is a new namespace
for configuration. For example, in 1.1, configuring a job looked like the
following:</para>
<programlisting>&lt;bean id="footballJob"
class="org.springframework.batch.core.job.SimpleJob"&gt;
&lt;property name="steps"&gt;
&lt;list&gt;
&lt;!-- Step bean details ommitted for clarity --&gt;
&lt;bean id="playerload"/&gt;
&lt;bean id="gameLoad"/&gt;
&lt;bean id="playerSummarization"/&gt;
&lt;/list&gt;
&lt;/property&gt;
&lt;property name="jobRepository" ref="jobRepository" /&gt;
&lt;/bean&gt;</programlisting>
<para>In 2.0, the equivalent would be:</para>
<programlisting>&lt;job id="footballJob"&gt;
&lt;!-- Step bean details ommitted for clarity --&gt;
&lt;step id="playerload" next="gameLoad"/&gt;
&lt;step id="gameLoad" next="playerSummarization"/&gt;
&lt;step id="playerSummarization"/&gt;
&lt;/job&gt;</programlisting>
<para>More information on how to configure Jobs and Steps with the new
namespace can be found in <xref linkend="configureJob" />, and <xref
linkend="configureStep" />.</para>
<para>The ability to retry an operation via the <classname>RetryTemplate</classname>
has always been a feature of Spring Batch. That ability has been identified as a
useful feature for other frameworks (Spring Integration for example). With the 2.2.0
release, the retry logic has been extracted from Spring Batch into it's own library
called Spring Retry. With this change, there are two main impacts. The first is
that the majority of the <literal>org.springframework.batch.retry</literal> package
has been moved into this new library. With that move, the package name has also
dropped the batch to become <literal>org.springframework.retry</literal>.</para>
</section>
<section id="whatsNewMetaDataAccess">
<title>Meta Data Access Improvements</title>
<section id="whatsNewJobParameters">
<title>Job Parameters</title>
<para>The <classname>JobRepository</classname> interface represents basic
CRUD operations with <classname>Job</classname> meta-data. However, it may
also be useful to query the meta-data. For that reason, the
<classname>JobExplorer</classname> and <classname>JobOperator</classname>
interfaces have been created:</para>
<para>Prior to the 2.2.0 release of Spring Batch, all parameters pass to a job execution
were used as part of the identity of the job. This limited the ability to change job
parameters during a rerun of a job. To accommodate this use case, 2.2.0 introduced the
idea of non-identifying job parameters.</para>
<mediaobject>
<imageobject role="html">
<imagedata align="center" fileref="images/job-repository-advanced.png"
scale="115" />
</imageobject>
<imageobject role="fo">
<imagedata align="center" fileref="images/job-repository-advanced.png"
scale="60" />
</imageobject>
</mediaobject>
<para>More information on the new meta data features can be found in <xref
linkend="advancedMetaData" />. It is also worth noting that Jobs can now
be stopped via the database, removing the requirement to maintain a handle
to the <classname>JobExecution</classname> on the JVM the job was launched
in.</para>
<para>By default, job parameters in 2.2.0 are still identifying. However, Spring Batch
now allows a user to specify a parameter not be used in the identity of a job instance.
In order to support this change, the domain model for batch changed. Before 2.2.0, job
parameters were associated with a <classname>JobInstance</classname>. 2.2.0 and beyond,
they are associated with a <classname>JobExecution</classname>. This also required the
underlying database schema for the job repository to change.</para>
</section>
<section id="whatsNewNonSequential">
<title>Non Sequential Step Execution</title>
<para>2.0 has also seen improvements in how steps can be configured.
Rather than requiring that they solely be sequential:</para>
<mediaobject>
<imageobject role="html">
<imagedata align="center" fileref="images/sequential-flow.png"
scale="20" />
</imageobject>
<imageobject role="fo">
<imagedata align="center" fileref="images/sequential-flow.png"
scale="45" />
</imageobject>
</mediaobject>
<para>They may now be conditional:</para>
<mediaobject>
<imageobject role="html">
<imagedata align="center" fileref="images/conditional-flow.png"
scale="50" />
</imageobject>
<imageobject role="fo">
<imagedata align="center" fileref="images/conditional-flow.png"
scale="45" />
</imageobject>
</mediaobject>
<para>This new 'conditional flow' support is made easy to configure via
the new namespace:</para>
<programlisting>&lt;job id="job"&gt;
&lt;step id="stepA"&gt;
&lt;next on="FAILED" to="stepB" /&gt;
&lt;next on="*" to="stepC" /&gt;
&lt;/step&gt;
&lt;step id="stepB" next="stepC" /&gt;
&lt;step id="stepC" /&gt;
&lt;/job&gt;</programlisting>
<para>More details on how to configure non sequential steps can be found
in <xref linkend="controllingStepFlow" />.</para>
</section>
<section id="whatsNewScalability">
<title>Scalability</title>
<para>Spring Batch 1.x was always intended as a single VM, possibly
multi-threaded model, but many features were built into it that support
parallel execution in multiple processes. Many projects have successfully
implemented a scalable solution relying on the quality of service features
of Spring Batch to ensure that processing only happens in the correct
sequence. In 2.0 those features have been exposed more explicitly. There
are two approaches to scalability: remote chunking, and
partitioning.</para>
<section id="whatsNewRemoteChunking">
<title>Remote Chunking</title>
<para>Remote chunking is a technique for dividing up the work of a step
without any explicit knowledge of the structure of the data. Any input
source can be split up dynamically by reading it in a single process (as
per normal in 1.x) and sending the items as a chunk to a remote worker
process. The remote process implements a listener pattern, responding to
the request, processing the data and sending an asynchronous reply. The
transport for the request and reply has to be durable with guaranteed
delivery and a single consumer, and those features are readily available
with any JMS implementation. But Spring Batch is building the remote
chunking feature on top of Spring Integration, therefore it is agnostic
to the actual implementation of the message middleware. More details can
be found in <xref linkend="remoteChunking" /></para>
</section>
<section id="whatsNewPartitioning">
<title>Partitioning</title>
<para>Partitioning is an alternative approach which in contrast depends
on having some knowledge of the structure of the input data, like a
range of primary keys, or the name of a file to process. The advantage
of this model is that the processors of each element in a partition can
act as if they are a single step in a normal Spring Batch job. They
don't have to implement any special or new patterns, which makes them
easy to configure and test. Partitioning in principle is more scalable
than remote chunking because there is no serialization bottleneck
arising from reading all the input data in one place.</para>
<para>In Spring Batch 2.0 partitioning is supported by two interfaces:
<classname>PartitionHandler</classname> and
<classname>StepExecutionSplitter</classname>. The
<classname>PartitionHandler</classname> is the one that knows about the
execution fabric - it has to transmit requests to remote steps and
collect the results using whatever grid or remoting technology is
available. <classname>PartitionHandler</classname> is an SPI, and Spring
Batch provides one implementation out of the box for local execution
through a <classname>TaskExecutor</classname>. This will be useful
immediately when parallel processing of heavily IO bound tasks is
required, since in those cases remote execution only complicates the
deployment and doesn't necessarily help much with the performance. Other
implementations will be specific to the execution fabric. (e.g. one of
the grid providers such as IBM, Oracle, Terracotta, Appistry etc.),
Spring Batch makes no preference for any of grid provider over another.
More details can be found in <xref linkend="partitioning" /></para>
</section>
</section>
</chapter>