Update namespace / 3.0 features in user guide
This commit is contained in:
@@ -202,16 +202,21 @@
|
||||
the PartitionStep is shown driving the execution. The PartitionStep
|
||||
configuration looks like this:</para>
|
||||
|
||||
<para><programlisting><bean name="step1:master" class="org.sfw...PartitionStep">
|
||||
<property name="partitionHandler" ref="partitionHandler"/>
|
||||
<property name="stepExecutionSplitter" ref="stepExecutionSplitter"/>
|
||||
<property name="jobRepository" ref="jobRepository" />
|
||||
</bean></programlisting></para>
|
||||
<para><programlisting><step id="step1.master">
|
||||
<partition step="step1" partitioner="partitioner">
|
||||
<handler grid-size="10" task-executor="taskExecutor"/>
|
||||
</partition>
|
||||
</step></programlisting></para>
|
||||
|
||||
<para>There is a simple example which can be copied and extended in the
|
||||
unit test suite for Spring Batch Core (see
|
||||
<classname>org.springframework.batch.core.partition</classname>
|
||||
package).</para>
|
||||
unit test suite for Spring Batch Samples (see
|
||||
<classname>*PartitionJob.xml</classname> configuration). </para>
|
||||
|
||||
<para>Spring Batch creates step executions for the partitions called
|
||||
"step1:partition0", etc., so many people prefer to call the master step
|
||||
"step1:master" for consistency. With Spring 3.0 you can do this using an
|
||||
alias for the step (specifying the <literal>name</literal> attribute
|
||||
instead of the <literal>id</literal>). </para>
|
||||
|
||||
<section id="partitionHandler">
|
||||
<title>PartitionHandler</title>
|
||||
@@ -240,10 +245,15 @@
|
||||
separate threads of execution, using the
|
||||
<classname>TaskExecutor</classname> strategy from Spring. The
|
||||
implementation is called
|
||||
<classname>TaskExecutorPartitionHandler</classname>, and it can be
|
||||
configured like this:</para>
|
||||
<classname>TaskExecutorPartitionHandler</classname>, and it is the
|
||||
default for a step configured with the XML namespace as above. It can
|
||||
also be configured explicitly like this:</para>
|
||||
|
||||
<para><programlisting><bean class="org.spr...TaskExecutorPartitionHandler">
|
||||
<para><programlisting><step id="step1.master">
|
||||
<partition step="step1" handler="handler"/>
|
||||
</step>
|
||||
|
||||
<bean class="org.spr...TaskExecutorPartitionHandler">
|
||||
<property name="taskExecutor" ref="taskExecutor"/>
|
||||
<property name="step" ref="step1" />
|
||||
<property name="gridSize" value="10" />
|
||||
@@ -257,38 +267,17 @@
|
||||
|
||||
<para>The <classname>TaskExecutorPartitionHandler</classname> is quite
|
||||
useful for IO intensive Steps, like copying large numbers of files or
|
||||
replicating filesystems into content management systems.</para>
|
||||
replicating filesystems into content management systems. It can also be
|
||||
used for remote execution by providing a Step implementation that is a
|
||||
proxy for a remote invocation (e.g. using Spring Remoting).</para>
|
||||
</section>
|
||||
|
||||
<section id="stepExecutionSplitter">
|
||||
<title>StepExecutionSplitter</title>
|
||||
<title>Partitioner</title>
|
||||
|
||||
<para>The <classname>StepExecutionSplitter</classname> is responsible
|
||||
for splitting up a <classname>StepExecution</classname> into blocks of
|
||||
work, and providing input parameters for the remote Slaves in the form
|
||||
of an <classname>ExecutionContext</classname> for each one. The
|
||||
principal method for this in the interface is</para>
|
||||
|
||||
<programlisting>public interface StepExecutionSplitter {
|
||||
...
|
||||
Set<StepExecution> split(StepExecution stepExecution, int gridSize)
|
||||
throws JobExecutionException;
|
||||
}</programlisting>
|
||||
|
||||
<para>So an execution instance for the Master step is passed in, along
|
||||
with a hint about the grid size, and the splitter has to create a set of
|
||||
partitioned <classname>StepExecution</classname> instances, each with a
|
||||
different <classname>ExecutionContext</classname>.</para>
|
||||
|
||||
<para>A convenient generic implementation of StepExecutionSplitter is
|
||||
provided by Spring Batch, which handles concerns like interpreting the
|
||||
grid size and handling restart. It is recommended that you use this
|
||||
implementation (the <classname>SimpleStepExecutionSplitter</classname>)
|
||||
and inject specific knowledge of the input data through its
|
||||
<classname>Partitioner</classname> property. The Partitioner has a
|
||||
simpler responsibility: to generate execution contexts as input
|
||||
parameters for new step executions only (no need to worry about
|
||||
restarts). It has a single method:</para>
|
||||
<para>The Partitioner has a simpler responsibility: to generate
|
||||
execution contexts as input parameters for new step executions only (no
|
||||
need to worry about restarts). It has a single method:</para>
|
||||
|
||||
<programlisting>public interface Partitioner {
|
||||
Map<String, ExecutionContext> partition(int gridSize);
|
||||
|
||||
@@ -1647,7 +1647,7 @@ itemWriter.write(items);</programlisting>
|
||||
|
||||
<programlisting><bean id="flatFileItemReader" scope="step"
|
||||
class="org.springframework.batch.item.file.FlatFileItemReader">
|
||||
<property name="resource" value="<emphasis role="bold">#{jobParameters[input.file.name]}</emphasis>" />
|
||||
<property name="resource" value="<emphasis role="bold">#{jobParameters['input.file.name']}</emphasis>" />
|
||||
</bean></programlisting>
|
||||
|
||||
<para>Both the <classname>JobExecution</classname> and
|
||||
@@ -1657,12 +1657,12 @@ itemWriter.write(items);</programlisting>
|
||||
|
||||
<programlisting><bean id="flatFileItemReader" scope="step"
|
||||
class="org.springframework.batch.item.file.FlatFileItemReader">
|
||||
<property name="resource" value="<emphasis role="bold">#{jobExecutionContext[input.file.name]}</emphasis>" />
|
||||
<property name="resource" value="<emphasis role="bold">#{jobExecutionContext['input.file.name']}</emphasis>" />
|
||||
</bean></programlisting>
|
||||
|
||||
<programlisting><bean id="flatFileItemReader" scope="step"
|
||||
class="org.springframework.batch.item.file.FlatFileItemReader">
|
||||
<property name="resource" value="<emphasis role="bold">#{stepExecutionContext[input.file.name]}</emphasis>" />
|
||||
<property name="resource" value="<emphasis role="bold">#{stepExecutionContext['input.file.name']}</emphasis>" />
|
||||
</bean></programlisting>
|
||||
|
||||
<note>
|
||||
@@ -1671,6 +1671,17 @@ itemWriter.write(items);</programlisting>
|
||||
information.</para>
|
||||
</note>
|
||||
|
||||
<note>
|
||||
<para>If you are using Spring 3.0 (or above) the expressions in
|
||||
step-scoped beans are in the Spring Expression Language, a powerful
|
||||
general purpose language with many interesting features. To provide
|
||||
backward compatibility, if Spring Batch detects the presence of older
|
||||
versions of Spring it uses a native expression language that is less
|
||||
powerful, and has slightly different parsing rules. The main difference
|
||||
is that the map keys in the example above do not need to be quoted with
|
||||
Spring 2.5, but the quotes are mandatory in Spring 3.0.</para>
|
||||
</note>
|
||||
|
||||
<section id="step-scope">
|
||||
<title>Step Scope</title>
|
||||
|
||||
|
||||
@@ -62,7 +62,10 @@ public class SkipSampleFunctionalTests extends AbstractJobTests { ... }</program
|
||||
<programlisting>@RunWith(SpringJUnit4ClassRunner.class)
|
||||
@ContextConfiguration(locations = { "/simple-job-launcher-context.xml",
|
||||
"/jobs/skipSampleJob.xml" })
|
||||
public class SkipSampleFunctionalTests extends AbstractJobTests {
|
||||
public class SkipSampleFunctionalTests {
|
||||
|
||||
@Autowired
|
||||
private JobLauncherTestUtils jobLauncherTestUtils;
|
||||
|
||||
private SimpleJdbcTemplate simpleJdbcTemplate;
|
||||
|
||||
@@ -80,7 +83,8 @@ public class SkipSampleFunctionalTests extends AbstractJobTests {
|
||||
i, "customer" + i);
|
||||
}
|
||||
|
||||
JobExecution jobExecution = <emphasis role="bold">this.launchJob()</emphasis>;
|
||||
JobExecution jobExecution = jobLauncherTestUtils.launchJob().getStatus();
|
||||
|
||||
|
||||
Assert.assertEquals("COMPLETED", jobExecution.getExitStatus());
|
||||
}
|
||||
@@ -99,7 +103,81 @@ public class SkipSampleFunctionalTests extends AbstractJobTests {
|
||||
targeted tests by allowing the test to set up data for just that step and
|
||||
to validate its results directly.</para>
|
||||
|
||||
<programlisting>JobExecution jobExecution = this.launchStep("loadFileStep");</programlisting>
|
||||
<programlisting>JobExecution jobExecution = jobLauncherTestUtils.launchStep("loadFileStep");</programlisting>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<title>Testing Step-Scoped Components</title>
|
||||
|
||||
<para>Often the components that are configured for your steps at runtime
|
||||
use step scope and late binding to inject context from the step or job
|
||||
execution. These are tricky to test as standalone components unless you
|
||||
have a way to set the context as if they were in a step execution. That is
|
||||
the goal of two components in Spring Batch: the
|
||||
<classname>StepScopeTestExecutionListener</classname> and the
|
||||
<classname>StepScopeTestUtils</classname>.</para>
|
||||
|
||||
<para>The listener is declared at the class level, and its job is to
|
||||
create a step execution context for each test method. For example:</para>
|
||||
|
||||
<programlisting>@ContextConfiguration
|
||||
@TestExecutionListeners( { DependencyInjectionTestExecutionListener.class,
|
||||
StepScopeTestExecutionListener.class })
|
||||
@RunWith(SpringJUnit4ClassRunner.class)
|
||||
public class StepScopeTestExecutionListenerIntegrationTests {
|
||||
|
||||
// This component is defined step-scoped, so it cannot be injected unless
|
||||
// a step is active...
|
||||
@Autowired
|
||||
private ItemReader<String> reader;
|
||||
|
||||
public StepExecution getStepExection() {
|
||||
StepExecution execution = MetaDataInstanceFactory.createStepExecution();
|
||||
execution.getExecutionContext().putString("input.data", "foo,bar,spam");
|
||||
return execution;
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testReader() {
|
||||
// The reader is initialized and bound to the input data
|
||||
assertNotNull(reader.read());
|
||||
}
|
||||
|
||||
}</programlisting>
|
||||
|
||||
<para>There are two <classname>TestExecutionListeners</classname>, one
|
||||
from the regular Spring Test framework and handles dependency injection
|
||||
from the configured application context, injecting the reader, and the
|
||||
other is the Spring Batch
|
||||
<classname>StepScopeTestExecutionListener</classname>. It works by looking
|
||||
for a factory method in the test case for a
|
||||
<classname>StepExecution</classname>, and using that as the context for
|
||||
the test method, as if that execution was active in a Step at runtime. The
|
||||
factory method is detected by its signature (it just has to return a
|
||||
<classname>StepExecution</classname>). If a factory method is not provided
|
||||
then a default <classname>StepExecution</classname> is created.</para>
|
||||
|
||||
<para>The listener approach is convenient if you want the duration of the
|
||||
step scope to be the execution of the test method. For a more flexible,
|
||||
but more invasive approach you can use the
|
||||
<classname>StepScopeTestUtils</classname>. For example, to count the
|
||||
number of items available in the reader above:</para>
|
||||
|
||||
<programlisting>int count = StepScopeTestUtils.doInStepScope(stepExecution,
|
||||
new Callable<Integer>() {
|
||||
|
||||
public Integer call() throws Exception {
|
||||
|
||||
int count = 0;
|
||||
|
||||
while (reader.read() != null) {
|
||||
count++;
|
||||
}
|
||||
|
||||
return count;
|
||||
|
||||
}
|
||||
});</programlisting>
|
||||
</section>
|
||||
|
||||
<section id="validatingOutputFiles">
|
||||
|
||||
Reference in New Issue
Block a user