From 506950484a503bdedf54fc32a60eb03b429bb911 Mon Sep 17 00:00:00 2001 From: dhgarrette Date: Fri, 13 Mar 2009 22:29:47 +0000 Subject: [PATCH] BATCH-1131: Updated docs to show the new way of configuring transaction attributes. --- src/site/docbook/reference/step.xml | 592 ++++++++++++++-------------- 1 file changed, 297 insertions(+), 295 deletions(-) diff --git a/src/site/docbook/reference/step.xml b/src/site/docbook/reference/step.xml index 87981cec8..54b294d4d 100644 --- a/src/site/docbook/reference/step.xml +++ b/src/site/docbook/reference/step.xml @@ -4,7 +4,7 @@ Configuring a Step - As discussed in , a + As discussed in , a Step is a domain object that encapsulates an independent, sequential phase of a batch job and contains all of the information necessary to define and control the actual batch processing. @@ -56,16 +56,16 @@ Below is a code representation of the same concepts shown above: - List items = new Arraylist(); - for(int i = 0; i < commitInterval; i++){ + for(int i = 0; i < commitInterval; i++){ Object item = itemReader.read() Object processedItem = itemProcessor.process(item); items.add(processedItem); } itemWriter.write(items); -]]> +
Configuring a Step @@ -75,14 +75,14 @@ potentially contain many collaborators. In order to ease configuration, the Spring Batch namespace can be used: - - - - - + + <job id="sampleJob"> + <step id="step1" job-repository="jobRepository" transaction-manager="transactionManager"> + <tasklet reader="itemReader" writer="itemWriter" commit-interval="10"/> + </step> + </job> -]]> + The configuration above represents the only required dependencies to create a item-oriented step: @@ -133,16 +133,16 @@ reference it from multiple jobs. This can be achieved with the 'ref' attribute: - - ref="standaloneStep" - + + <job id="sampleJob"> + <step id="step1" ref="standaloneStep" /> + </job> - - - + <step id="standaloneStep" job-repository="jobRepository" transaction-manager="transactionManager"> + <tasklet reader="itemReader" writer="itemWriter" commit-interval="10"/> + </step> -]]> + It should be noted that the id attribute is still required on the step within the job element. This is for two reasons: @@ -177,15 +177,15 @@ number of items that are processed within a commit can be configured. - - - commit-interval="10" - - + + <job id="sampleJob"> + <step id="step1" job-repository="jobRepository" transaction-manager="transactionManager"> + <tasklet reader="itemReader" writer="itemWriter" commit-interval="10"/> + </step> + </job> -]]> + In the example above, 10 items will be processed within each transaction. At the beginning of processing a transaction is begun, and @@ -217,13 +217,13 @@ as a Step that can be run infinitely. Below is an example start limit configuration: - - start-limit="1" - + + <step id="step1"> + <tasklet reader="itemReader" writer="itemWriter" commit-interval="10" start-limit="1"/> + </step> -]]> + The simple step above can be run only once. Attempting to run it again will cause an exception to be thrown. It should be noted that @@ -243,35 +243,35 @@ successfully, will be skipped. Setting allow-start-if-complete to "true" overrides this so that the step will always run: - - allow-start-if-complete="true" - + + <step id="step1"> + <tasklet reader="itemReader" writer="itemWriter" commit-interval="10" + allow-start-if-complete="true"/> + </step> -]]> +
Step restart configuration example - - - - - - - - - - - + + <job id="footballJob" restartable="true"> + <step id="playerload" next="gameLoad"> + <tasklet reader="playerFileItemReader" writer="playerWriter" + commit-interval="10" /> + </step> + <step id="gameLoad" next="playerSummarization"> + <tasklet reader="gameFileItemReader" writer="gameWriter" + commit-interval="10" allow-start-if-complete="true"/> + </step> + <step id="playerSummarization"> + <tasklet reader="playerSummarizationSource" writer="summaryWriter" + commit-interval="10" start-limit="3"/> + </step> + </job> -]]> + The above example configuration is for a job that loads in information about football games and summarizes them. It contains @@ -384,17 +384,17 @@ loaded because it was formatted incorrectly or was missing necessary information, then there probably won't be issues. Usually these bad records are logged as well, which will be covered later when discussing - listeners. - skip-limit="10" - ]]><skippable-exception-classes> + listeners. + <step id="step1"> + <tasklet reader="flatFileItemReader" writer="itemWriter" commit-interval="10" skip-limit="10"> + <skippable-exception-classes> org.springframework.batch.item.file.FlatFileParseException - </skippable-exception-classes> - + </skippable-exception-classes> + </tasklet> + </step> -]]> + In this example, a FlatFileItemReader is used, and if at any point a @@ -407,25 +407,26 @@
Configuring Fatal Exceptions + One problem with the example above is that any other exception besides a FlatFileParseException will cause the Job to fail. In certain scenarios this may be the correct behavior. However, in other scenarios it may be easier to identify which exceptions should cause failure and skip everything - else: - skip-limit="10" -]]> <skippable-exception-classes> + else: + <step id="step1"> + <tasklet reader="flatFileItemReader" writer="itemWriter" commit-interval="10" skip-limit="10"> + <skippable-exception-classes> java.lang.Exception </skippable-exception-classes> <fatal-exception-classes> java.io.FileNotFoundException </fatal-exception-classes> - - + </tasklet> + </step> -]]> + By setting the skippable exceptions to java.lang.Exception, any exception that is thrown @@ -447,17 +448,17 @@ process holds a lock on, waiting and trying again might result in success. In this case, retry should be configured: - - retry-limit="3" - ]]><retryable-exception-classes> + + <step id="step1"> + <tasklet reader="itemReader" writer="itemWriter" commit-interval="2" retry-limit="3"> + <retryable-exception-classes> org.springframework.dao.DeadlockLoserDataAccessException - </retryable-exception-classes> - + </retryable-exception-classes> + </tasklet> + </step> -]]> + The Step allows a limit for the number of times an individual item can be retried, and a list of exceptions that @@ -477,23 +478,24 @@ ItemWriter should not cause a rollback because no action has taken place to invalidate the transaction. For this reason, the Step can be configured with a list of - exceptions that should not cause rollback. The transaction-attribute - attribute is a comma-separated list. Prefixing a class name with the "+" - symbol will indicate that that exception should not cause - rollback. + exceptions that should not cause rollback. The transaction-attributes + element is a list of transaction attributes, separated by commas or + newlines. Prefixing a class name with the "+" symbol will indicate that + that exception should not cause rollback. - - transaction-attribute="+org.springframework.batch.item.validator.ValidationException" - - + + <step id="step1"> + <tasklet reader="itemReader" writer="itemWriter" commit-interval="2" skip-limit="1"/> + <transaction-attributes> + +org.springframework.batch.item.validator.ValidationException + </transaction-attributes> + </step> -]]> + - Transaction attributes can be used to control multiple other - settings such as isolation and propagation behavior. More information on - setting transaction attributes can be found in the spring core + Transaction attributes can also be used to control other settings + such as isolation and propagation behavior. More information on setting + transaction attributes can be found in the spring core documentation.
@@ -509,14 +511,14 @@ this reason, the step can be configured to not buffer the items: - - is-reader-transactional-queue="true" - - + + <step id="step1"> + <tasklet reader="itemReader" writer="itemWriter" commit-interval="2" skip-limit="1" + is-reader-transactional-queue="true"> + </tasklet> + </step> -]]> +
@@ -541,27 +543,27 @@ can be registered on the Step through the 'streams' element, as illustrated below:
- - - ]]><streams> + + <step id="step1"> + <tasklet reader="itemReader" writer="compositeWriter" commit-interval="2"> + <streams> <stream ref="fileItemWriter1"/> <stream ref="fileItemWriter2"/> - </streams> - + </streams> + </tasklet> + </step> - - - - - - - - + <beans:bean id="compositeWriter" + class="org.springframework.batch.item.support.CompositeItemWriter"> + <beans:property name="delegates"> + <beans:list> + <beans:ref bean="fileItemWriter1" /> + <beans:ref bean="fileItemWriter2" /> + </beans:list> + </beans:property> + </beans:bean> -]]> + In the example above, the CompositeItemWriter is not an @@ -591,15 +593,15 @@ interface (or an extension thereof) can be applied to a step via the listeners element: - - - - - - + + <step id="step1"> + <tasklet reader="reader" writer="writer" commit-interval="10"/> + <listeners> + <listener ref="stepListener"/> + </listeners> + </step> -]]> + In addition to the StepListener interfaces, annotations are provided to address the same concerns. @@ -612,7 +614,7 @@ for notification before a Step is started and after it has ends, whether it ended normally or failed: - public interface StepExecutionListener extends StepListener { void beforeStep(StepExecution stepExecution); @@ -620,7 +622,7 @@ ExitStatus afterStep(StepExecution stepExecution); } -]]> + ExitStatus is the return type of afterStep in order to allow listeners the @@ -649,12 +651,12 @@ useful to perform logic before a chunk begins processing or after a chunk has completed: - public interface ChunkListener extends StepListener { void beforeChunk(); void afterChunk(); - }]]> + } The beforeChunk method is called after the transaction is started, but before read @@ -683,14 +685,14 @@ When discussing skip logic above, it was mentioned that it may be beneficial to log out skipped records, so that they can be deal with later. In the case of read errors, this can be done with an - ItemReaderListener: extends StepListener { + ItemReaderListener: public interface ItemReadListener<T> extends StepListener { void beforeRead(); void afterRead(T item); void onReadError(Exception ex); -}]]> +} The beforeRead method will be called before each call to read on the @@ -725,14 +727,14 @@ Just as with the ItemReadListener, the processing of an item can be 'listened' to: - extends StepListener { + public interface ItemProcessListener<T, S> extends StepListener { void beforeProcess(T item); void afterProcess(T item, S result); void onProcessError(T item, Exception e); -}]]> +} The beforeProcess method will be called before process on the @@ -767,14 +769,14 @@ The writing of an item can be 'listened' to with the ItemWriteListener: - extends StepListener { + public interface ItemWriteListener<S> extends StepListener { - void beforeWrite(List items); + void beforeWrite(List<? extends S> items); - void afterWrite(List items); + void afterWrite(List<? extends S> items); - void onWriteError(Exception exception, List items); -}]]> + void onWriteError(Exception exception, List<? extends S> items); +} The beforeWrite method will be called before write on the @@ -814,8 +816,8 @@ this reason, there is a separate interface for tracking skipped items: - extends StepListener { + + public interface SkipListener<T,S> extends StepListener { void onSkipInRead(Throwable t); @@ -824,7 +826,7 @@ void onSkipInWrite(S item, Throwable t); } -]]> + onSkipInRead will be called whenever an item is skipped while reading. It should be noted that rollbacks may @@ -900,10 +902,10 @@ Tasklet object; no 'tasklet' element is needed within the 'step': - tasklet="myTasklet" + + <step id="step1" tasklet="myTasklet" /> -]]> + TaskletStep will automatically register the @@ -924,15 +926,15 @@ this class without having to write an adapter for the Tasklet interface: - - - - - - + + <bean id="myTasklet" class="org.springframework.batch.core.step.tasklet.TaskletAdapter"> + <property name="targetObject"> + <bean class="org.mycompany.FooDao"> + </property> + <property name="targetMethod" value-"updateFoo" /> + </bean> -]]> +
@@ -947,7 +949,7 @@ project, is a Tasklet implementation with just such a responsibility: - public class FileDeletingTasklet implements Tasklet, InitializingBean { private Resource directory; @@ -956,7 +958,7 @@ Assert.state(dir.isDirectory()); File[] files = dir.listFiles(); - for (int i = 0; i < files.length; i++) { + for (int i = 0; i < files.length; i++) { boolean deleted = files[i].delete(); if (!deleted) { throw new UnexpectedJobExecutionException("Could not delete file " + files[i].getPath()); @@ -972,7 +974,7 @@ public void afterPropertiesSet() throws Exception { Assert.notNull(directory, "directory must be set"); } - }]]> + } The above Tasklet implementation will delete all files within a given directory. It should be noted that the @@ -980,22 +982,22 @@ that is left is to reference the Tasklet from the Step: - - - + + <job id="taskletJob"> + <step id="deleteFilesInDir" tasklet="fileDeletingTasklet"/> + </job> - - - - - - - + <bean id="fileDeletingTasklet" + class="org.springframework.batch.sample.tasklet.FileDeletingTasklet"> + <property name="directoryResource"> + <bean id="directory" + class="org.springframework.core.io.FileSystemResource"> + <constructor-arg value="target/test-outputs/test-dir" /> + </bean> + </property> + </bean> -]]> +
@@ -1032,18 +1034,18 @@ This can be achieved using the 'next' attribute of the step element: - - - - - + + <job id="job"> + <step id="stepA" next="stepB" /> + <step id="stepB" next="stepC"/> + <step id="stepC" /> + </job> -]]>In the scenario above, 'step A' will execute first because - it is the first Step listed. If 'step A' - completes normally, then 'step B' will execute, and so on. However, if - 'step A' fails, then the entire Job will fail and - 'step B' will not execute. +In the scenario above, 'step A' will execute first because it + is the first Step listed. If 'step A' completes + normally, then 'step B' will execute, and so on. However, if 'step A' + fails, then the entire Job will fail and 'step B' + will not execute. With the Spring Batch namespace, the first step listed in the @@ -1101,17 +1103,17 @@ The next element specifies a pattern to match and the step to execute next: - - - - - - - - + + <job id="job"> + <step id="stepA"> + <next on="FAILED" to="stepB" /> + <next on="*" to="stepC" /> + </step> + <step id="stepB" next="stepC" /> + <step id="stepC" /> + </job> -]]> + The "on" attribute of a transition element uses a simple pattern-matching scheme to match the ExitStatus @@ -1159,10 +1161,10 @@ it fails, and so on. The example above contains the following 'next' element: - + + <next on="FAILED" to="stepB" /> -]]> + At first glance, it would appear that the 'on' attribute references the BatchStatus of the @@ -1179,14 +1181,14 @@ code needs to be different? A good example comes from the skip sample job within the samples project: - - - - - + + <step id="step1"> + <end on="FAILED" /> + <next on="COMPLETED WITH SKIPS" to="errorPrint1" /> + <next on="*" to="step2" /> + </step> -]]> + The above step has three possibilities: @@ -1212,18 +1214,18 @@ change the exit code based on the condition of the execution having skipped records: - public class SkipCheckingListener extends StepExecutionListenerSupport { public ExitStatus afterStep(StepExecution stepExecution) { if (!stepExecution.getExitStatus().getExitCode().equals(ExitStatus.FAILED.getExitCode()) - && stepExecution.getSkipCount() > 0) { + && stepExecution.getSkipCount() > 0) { return new ExitStatus("COMPLETED WITH SKIPS"); } else { return null; } } - }]]> + } The above code is a StepExecutionListener that first checks to make sure the Step was @@ -1251,7 +1253,7 @@ after the following step executes, the Job will end: - ]]> + <step id="stepC" /> If no transitions are defined for a Step, then the Job's statuses will be defined as @@ -1310,12 +1312,12 @@ fails, the Job will not be restartable (because the status is COMPLETED). - - - - - - ]]> + <step id="step1" next="step2"> + <step id="step2"> + <end on="FAILED"/> + <next on="*" to="step3"/> + </step> + <step id="step3">
@@ -1339,12 +1341,12 @@ Additionally, if step2 fails, and the Job is restarted, then execution will begin again on step2. - - - - - - ]]> + <step id="step1" next="step2"> + <step id="step2"> + <fail on="FAILED" exit-code="EARLY TERMINATION"/> + <next on="*" to="step3"/> + </step> + <step id="step3">
@@ -1362,10 +1364,10 @@ the job will then stop. Once it is restarted, execution will begin on step2. - - - - ]]> + <step id="step1"> + <stop on="COMPLETED" restart="step2"/> + </step> + <step id="step2"/>
@@ -1378,7 +1380,7 @@ JobExecutionDecider can be used to assist in the decision.
- public class MyDecider implements JobExecutionDecider { public String decide(JobExecution jobExecution, StepExecution stepExecution) { @@ -1392,27 +1394,27 @@ } -]]> +
In the job configuration, a "decision" tag will specify the decider to use as well as all of the transitions. - - + + <job id="job"> + <step id="step1" next="decision" /> - - - - + <decision id="skipCheckingDecision" decider="decider"> + <next on="FAILED" to="step2" /> + <next on="COMPLETED" to="step3" /> + </step> - - - + <step id="step2" next="step3"/> + <step id="step3" /> + </job> - + <bean id="decider" class="com.MyDecider"/> -]]> +
@@ -1429,16 +1431,16 @@ elements such as the 'next' attribute or the 'next', 'end', 'fail', or 'pause' elements. - - - - - - - - - - ]]> + <split id="split1" next="step4"> + <flow> + <step id="step1" next="step2"/> + <step id="step2"/> + </flow> + <flow> + <step id="step3"/> + </flow> + </split> + <step id="step4"/>
@@ -1452,14 +1454,14 @@ Flat File resources can be configured using standard Spring constructs: - - - + + <bean id="flatFileItemReader" + class="org.springframework.batch.item.file.FlatFileItemReader"> + <property name="resource" + value="file://outputs/20070122.testStream.CustomerReportStep.TEMP.txt" /> + </bean> -]]> + The above Resource will load the file from the file system location specified. Note that absolute locations have to @@ -1469,13 +1471,13 @@ at runtime as a parameter to the job. This could be solved using '-D' parameters, i.e. a system property: - - - + + <bean id="flatFileItemReader" + class="org.springframework.batch.item.file.FlatFileItemReader"> + <property name="resource" value="${input.file.name}" /> + </bean> -]]> + All that would be required for this solution to work would be a system argument (-Dinput.file.name="file://file.txt"). (Note that although @@ -1491,34 +1493,34 @@ accomplish this, Spring Batch allows for the late binding of various Job and Step attributes: - - #{jobParameters[input.file.name]} - + + <bean id="flatFileItemReader" scope="step" + class="org.springframework.batch.item.file.FlatFileItemReader"> + <property name="resource" value="#{jobParameters[input.file.name]}" /> + </bean> -]]> + Both the JobExecution and StepExecution level ExecutionContext can be accessed in the same way: - - #{jobExecutionContext[input.file.name]} - + + <bean id="flatFileItemReader" scope="step" + class="org.springframework.batch.item.file.FlatFileItemReader"> + <property name="resource" value="#{jobExecutionContext[input.file.name]}" /> + </bean> -]]> + - - #{stepExecutionContext[input.file.name]} - + + <bean id="flatFileItemReader" scope="step" + class="org.springframework.batch.item.file.FlatFileItemReader"> + <property name="resource" value="#{stepExecutionContext[input.file.name]}" /> + </bean> -]]> +
Step Scope @@ -1526,37 +1528,37 @@ All of the late binding examples from above have a scope of "step" declared on the bean definition: - scope="step" - - + + <bean id="flatFileItemReader" scope="step" + class="org.springframework.batch.item.file.FlatFileItemReader"> + <property name="resource" value="#{jobParameters[input.file.name]}" /> + </bean> -]]> + Using a scope of Step is required in order to use late binding since the bean cannot actually be instantiated until the Step starts, which allows the attributes to be found. Because it is not part of the Spring container by default, it - must be added explicitly, either by using the batch - namespace: + must be added explicitly, either by using the batch + namespace: - +<beans xmlns="http://www.springframework.org/schema/beans" xmlns:batch="http://www.springframework.org/schema/batch" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" - xsi:schemaLocation="..."> + xsi:schemaLocation="..."> ... - -]]> +</beans> + - or by including a bean definition explicitly for theStep (but not both): + or by including a bean definition explicitly for + theStep (but not both): - - -]]> + + <bean class="org.springframework.batch.core.scope.StepScope" /> +