From 38d6e7d496c10e352ae04bc64fd45f9a4f4c89b2 Mon Sep 17 00:00:00 2001 From: Jay Bryant Date: Thu, 19 Oct 2017 17:32:58 -0500 Subject: [PATCH] 90-character pass for step.adoc I removed extraneous white space from non-code lines and arranged the non-code lines to be as close to 90 characters as possible. I also edited the new content. Applied code review changes --- spring-batch-docs/asciidoc/step.adoc | 1555 +++++++++----------------- 1 file changed, 555 insertions(+), 1000 deletions(-) diff --git a/spring-batch-docs/asciidoc/step.adoc b/spring-batch-docs/asciidoc/step.adoc index dd3d16850..7899bfcd4 100644 --- a/spring-batch-docs/asciidoc/step.adoc +++ b/spring-batch-docs/asciidoc/step.adoc @@ -7,41 +7,35 @@ include::toggle.adoc[] -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. - This is a necessarily vague description because the contents of any given - `Step` are at the discretion of the developer writing a - `Job`. A `Step` can be as simple or complex as the - developer desires. A simple `Step` might load data from - a file into the database, requiring little or no code (depending upon the - implementations used). A more complex `Step` might have - complicated business rules that are applied as part of the - processing, as shown in the following image: +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. This is a necessarily vague description because the contents of any given +`Step` are at the discretion of the developer writing a `Job`. A `Step` can be as simple +or complex as the developer desires. A simple `Step` might load data from a file into the +database, requiring little or no code (depending upon the implementations used). A more +complex `Step` might have complicated business rules that are applied as part of the +processing, as shown in the following image: .Step image::{batch-asciidoc}images/step.png[Step, scaledwidth="60%"] [[chunkOrientedProcessing]] - === Chunk-oriented Processing -Spring Batch uses a 'Chunk-oriented' processing style within its - most common implementation. Chunk oriented processing refers to reading - the data one at a time and creating 'chunks' that are written out - within a transaction boundary. One item is read in from an - `ItemReader`, handed to an - `ItemProcessor`, and aggregated. Once the number of - items read equals the commit interval, the entire chunk is written out by - the `ItemWriter`, and then the transaction is committed. The following image shows the process: +Spring Batch uses a 'Chunk-oriented' processing style within its most common +implementation. Chunk oriented processing refers to reading the data one at a time and +creating 'chunks' that are written out within a transaction boundary. One item is read in +from an `ItemReader`, handed to an `ItemProcessor`, and aggregated. Once the number of +items read equals the commit interval, the entire chunk is written out by the +`ItemWriter`, and then the transaction is committed. The following image shows the +process: .Chunk-oriented Processing image::{batch-asciidoc}images/chunk-oriented-processing.png[Chunk Oriented Processing, scaledwidth="60%"] The following code shows the same concepts shown: - [source, java] ---- List items = new Arraylist(); @@ -54,17 +48,14 @@ itemWriter.write(items); ---- [[configuringAStep]] - - ==== Configuring a `Step` -Despite the relatively short list of required dependencies for a - `Step`, it is an extremely complex class that can - potentially contain many collaborators. +Despite the relatively short list of required dependencies for a `Step`, it is an +extremely complex class that can potentially contain many collaborators. [role="xmlContent"] -In order to ease configuration, - the Spring Batch namespace can be used, as shown in the following example: +In order to ease configuration, the Spring Batch namespace can be used, as shown in the +following example: .XML Configuration [source, xml, role="xmlContent"] @@ -79,9 +70,8 @@ In order to ease configuration, ---- [role="javaContent"] -When using java configuration, - the Spring Batch builders can be used, as shown in the following example: - +When using java configuration, the Spring Batch builders can be used, as shown in the +following example: .Java Configuration [source, java, role="javaContent"] @@ -114,126 +104,87 @@ public Step sampleStep(PlatformTransactionManager transactionManager) { ---- ifdef::backend-html5[] -The configuration above includes the only required dependencies - to create a item-oriented step: +The configuration above includes the only required dependencies to create a item-oriented +step: -* `reader`: The `ItemReader` that provides - items for processing. - - -* `writer`: The ItemWriter that - processes the items provided by the - `ItemReader`. +* `reader`: The `ItemReader` that provides items for processing. +* `writer`: The ItemWriter that processes the items provided by the`ItemReader`. [role="xmlContent"] -* `transaction-manager`: Spring's - `PlatformTransactionManager` that - begins and commits transactions during processing. +* `transaction-manager`: Spring's `PlatformTransactionManager` that begins and commits +transactions during processing. [role="javaContent"] -* `transactionManager`: Spring's - `PlatformTransactionManager` that - begins and commits transactions during processing. +* `transactionManager`: Spring's `PlatformTransactionManager` that begins and commits +transactions during processing. [role="xmlContent"] -* `job-repository`: The `JobRepository` - that periodically stores the - `StepExecution` and - `ExecutionContext` during processing (just - before committing). For an in-line (one defined - within a ), it is an attribute on the - element. For a standalone step, it is defined as an attribute of - the . +* `job-repository`: The `JobRepository` that periodically stores the `StepExecution` and +`ExecutionContext` during processing (just before committing). For an in-line +(one defined within a ), it is an attribute on the element. For a standalone +step, it is defined as an attribute of the . [role="javaContent"] -* `repository`: The `JobRepository` - that periodically stores the - `StepExecution` and - `ExecutionContext` during processing (just - before committing). +* `repository`: The `JobRepository` that periodically stores the `StepExecution` and +`ExecutionContext` during processing (just before committing). [role="xmlContent"] -* `commit-interval`: The number of items to be processed - before the transaction is committed. +* `commit-interval`: The number of items to be processed before the transaction is +committed. [role="javaContent"] -* `chunk`: Indicates that this is an item based step and the number of items to be processed - before the transaction is committed. - +* `chunk`: Indicates that this is an item based step and the number of items to be +processed before the transaction is committed. [role="xmlContent"] -It should be noted that `job-repository` defaults to - `jobRepository` and `transaction-manager` defaults to `transactionManger`. - Also, the `ItemProcessor` is optional, - since the item could be directly passed from the reader to the - writer. +It should be noted that `job-repository` defaults to `jobRepository` and +`transaction-manager` defaults to `transactionManger`. Also, the `ItemProcessor` is +optional, since the item could be directly passed from the reader to the writer. [role="javaContent"] -It should be noted that `repository` defaults to - `jobRepository` and `transactionManager` defaults to `transactionManger` (all - provided via the infrastructure from `@EnableBatchProcessing`). - Also, the `ItemProcessor` is optional, - since the item could be directly passed from the reader to the - writer. +It should be noted that `repository` defaults to `jobRepository` and `transactionManager` +defaults to `transactionManger` (all provided through the infrastructure from +`@EnableBatchProcessing`). Also, the `ItemProcessor` is optional, since the item could be +directly passed from the reader to the writer. endif::backend-html5[] ifdef::backend-pdf[] -The configuration above includes the only required dependencies - to create a item-oriented step: +The configuration above includes the only required dependencies to create a item-oriented +step: -* `reader`: The `ItemReader` that provides - items for processing. +* `reader`: The `ItemReader` that provides items for processing. +* `writer`: The ItemWriter that processes the items provided by the `ItemReader`. +* `transaction-manager`/`transactionManager`: Spring's `PlatformTransactionManager` that +begins and commits transactions during processing. +* `job-repository`/`repository`: The `JobRepository` that periodically stores the +`StepExecution` and `ExecutionContext` during processing (just before committing). In +XML, for an in-line (one defined within a ``), it is an attribute on the +`` element. For a standalone step, it is defined as an attribute of the +``. +* `commit-interval`/`chunk`: The number of items to be processed before the transaction +is committed. - -* `writer`: The ItemWriter that - processes the items provided by the - `ItemReader`. - -* `transaction-manager`/`transactionManager`: Spring's - `PlatformTransactionManager` that - begins and commits transactions during processing. - -* `job-repository`/`repository`: The `JobRepository` - that periodically stores the - `StepExecution` and - `ExecutionContext` during processing (just - before committing). In XML, for an in-line (one defined - within a ), it is an attribute on the - element. For a standalone step, it is defined as an attribute of - the . - -* `commit-interval`/`chunk`: The number of items to be processed - before the transaction is committed. - -It should be noted that `job-repository`/`repository` defaults to - `jobRepository` and `transaction-manager`/`transactionManager` defaults to - `transactionManger`. Also, the `ItemProcessor` is optional, - since the item could be directly passed from the reader to the - writer. +It should be noted that `job-repository`/`repository` defaults to `jobRepository` and +`transaction-manager`/`transactionManager` defaults to `transactionManager`. Also, the +`ItemProcessor` is optional, since the item could be directly passed from the reader to +the writer. endif::backend-pdf[] - [[InheritingFromParentStep]] - [role="xmlContent"] ==== Inheriting from a Parent `Step` [role="xmlContent"] -If a group of `Steps` share similar - configurations, then it may be helpful to define a "parent" - `Step` from which the concrete - `Steps` may inherit properties. Similar to class - inheritance in Java, the "child" `Step` - combines its elements and attributes with the parent's. The child - also overrides any of the parent's `Steps`. +If a group of `Steps` share similar configurations, then it may be helpful to define a +"parent" `Step` from which the concrete `Steps` may inherit properties. Similar to class +inheritance in Java, the "child" `Step` combines its elements and attributes with the +parent's. The child also overrides any of the parent's `Steps`. [role="xmlContent"] -In the following example, the `Step`, - "concreteStep1", inherits from "parentStep". It will be instantiated - with 'itemReader', 'itemProcessor', 'itemWriter', `startLimit=5`, and - `allowStartIfComplete=true`. Additionally, the `commitInterval` is '5', - since it is overridden by the "concreteStep1" `Step`, as shown in the following example: - +In the following example, the `Step`, "concreteStep1", inherits from "parentStep". It is +instantiated with 'itemReader', 'itemProcessor', 'itemWriter', `startLimit=5`, and +`allowStartIfComplete=true`. Additionally, the `commitInterval` is '5', since it is +overridden by the "concreteStep1" `Step`, as shown in the following example: [source, xml, role="xmlContent"] ---- @@ -251,41 +202,30 @@ In the following example, the `Step`, ---- [role="xmlContent"] -The `id` attribute is still required on the step within the job - element. This is for two reasons: -. The `id` is used as the step name when persisting the - `StepExecution`. If the same standalone step is referenced in more - than one step in the job, an error will occur. - +The `id` attribute is still required on the step within the job element. This is for two +reasons: +* The `id` is used as the step name when persisting the `StepExecution`. If the same +standalone step is referenced in more than one step in the job, an error occurs. [role="xmlContent"] -. When creating job flows, as described later in this chapter, - the `next` attribute should be referring to the step in the flow, - not the standalone step. - - +* When creating job flows, as described later in this chapter, the `next` attribute +should be referring to the step in the flow, not the standalone step. [[abstractStep]] - [role="xmlContent"] ===== Abstract `Step` [role="xmlContent"] -Sometimes, it may be necessary to define a parent - `Step` that is not a complete - `Step` configuration. If, for instance, the - `reader`, `writer`, and `tasklet` attributes are left off of a - `Step` configuration, then initialization will - fail. If a parent must be defined without these properties, then the - `abstract` attribute should be used. An `abstract` - `Step` is only extended, never instantiated. +Sometimes, it may be necessary to define a parent `Step` that is not a complete `Step` +configuration. If, for instance, the `reader`, `writer`, and `tasklet` attributes are +left off of a `Step` configuration, then initialization fails. If a parent must be +defined without these properties, then the `abstract` attribute should be used. An +`abstract` `Step` is only extended, never instantiated. [role="xmlContent"] -In the following example, the `Step` - `abstractParentStep` would not be instantiated if it were not declared to - be abstract. The `Step`, "concreteStep2", has - 'itemReader', 'itemWriter', and commitInterval=10. - +In the following example, the `Step` `abstractParentStep` would not be instantiated if it +were not declared to be abstract. The `Step`, "concreteStep2", has 'itemReader', +'itemWriter', and commitInterval=10. [source, xml, role="xmlContent"] ---- @@ -303,27 +243,20 @@ In the following example, the `Step` ---- [[mergingListsOnStep]] - [role="xmlContent"] ===== Merging Lists [role="xmlContent"] -Some of the configurable elements on - `Steps` are lists. The `` - element, for instance. If both the parent and child - `Steps` declare a `` element, - then the child's list overrides the parent's. In order to allow a - child to add additional listeners to the list defined by the parent, - every list element has a `merge` attribute. If the element specifies - that `merge="true"`, then the child's list is combined with the - parent's instead of overriding it. +Some of the configurable elements on `Steps` are lists. The `` element, for +instance. If both the parent and child `Steps` declare a `` element, then the +child's list overrides the parent's. In order to allow a child to add additional +listeners to the list defined by the parent, every list element has a `merge` attribute. +If the element specifies that `merge="true"`, then the child's list is combined with the +parent's instead of overriding it. [role="xmlContent"] -In the following example, the `Step`, - "concreteStep3", is created with two listeners: - `listenerOne` and - `listenerTwo`: - +In the following example, the `Step`, "concreteStep3", is created with two listeners: +`listenerOne` and `listenerTwo`: [source, xml, role="xmlContent"] ---- @@ -344,23 +277,17 @@ In the following example, the `Step`, ---- [[commitInterval]] - - ==== The Commit Interval -As mentioned previously, a step reads in and writes out items, - periodically committing using the supplied - `PlatformTransactionManager`. With a - `commit-interval` of 1, it commits after writing each individual item. - This is less than ideal in many situations, since beginning and - committing a transaction is expensive. Ideally, it is preferable to - process as many items as possible in each transaction, which is - completely dependent upon the type of data being processed and the - resources with which the step is interacting. For this reason, the - number of items that are processed within a commit can be - configured. The following example shows a `step` whose `tasklet` has a - `commit-interval` value of 10. - +As mentioned previously, a step reads in and writes out items, periodically committing +using the supplied `PlatformTransactionManager`. With a `commit-interval` of 1, it +commits after writing each individual item. This is less than ideal in many situations, +since beginning and committing a transaction is expensive. Ideally, it is preferable to +process as many items as possible in each transaction, which is completely dependent upon +the type of data being processed and the resources with which the step is interacting. +For this reason, the number of items that are processed within a commit can be +configured. The following example shows a `step` whose `tasklet` has a `commit-interval` +value of 10. .XML Configuration [source, xml, role="xmlContent"] @@ -395,38 +322,28 @@ public Step step1() { } ---- -In the preceding example, 10 items are processed within each - transaction. At the beginning of processing, a transaction is begun. Also, - each time `read` is called on the - `ItemReader`, a counter is incremented. When it - reaches 10, the list of aggregated items is passed to the - `ItemWriter`, and the transaction is - committed. +In the preceding example, 10 items are processed within each transaction. At the +beginning of processing, a transaction is begun. Also, each time `read` is called on the +`ItemReader`, a counter is incremented. When it reaches 10, the list of aggregated items +is passed to the `ItemWriter`, and the transaction is committed. [[stepRestart]] - - ==== Configuring a `Step` for Restart In the "<>" section , restarting a - `Job` was discussed. Restart has numerous impacts - on steps, and, consequently, may require some specific configuration. +`Job` was discussed. Restart has numerous impacts on steps, and, consequently, may +require some specific configuration. [[startLimit]] - - ===== Setting a Start Limit -There are many scenarios where you may want to control the - number of times a `Step` may be started. For - example, a particular `Step` might need to be - configured so that it only runs once because it invalidates some - resource that must be fixed manually before it can be run again. This - is configurable on the step level, since different steps may have - different requirements. A `Step` that may only be - executed once can exist as part of the same `Job` - as a `Step` that can be run infinitely. The following code fragment shows - an example of a start limit configuration: +There are many scenarios where you may want to control the number of times a `Step` may +be started. For example, a particular `Step` might need to be configured so that it only +runs once because it invalidates some resource that must be fixed manually before it can +be run again. This is configurable on the step level, since different steps may have +different requirements. A `Step` that may only be executed once can exist as part of the +same `Job` as a `Step` that can be run infinitely. The following code fragment shows an +example of a start limit configuration: .XML Configuration [source, xml, role="xmlContent"] @@ -452,24 +369,19 @@ public Step step1() { } ---- -The step above can be run only once. Attempting to run it - again causes a `StartLimitExceededException` to be thrown. Note that - the default value for the start-limit is - `Integer.MAX_VALUE`. +The step above can be run only once. Attempting to run it again causes a +`StartLimitExceededException` to be thrown. Note that the default value for the +start-limit is `Integer.MAX_VALUE`. [[allowStartIfComplete]] - - ===== Restarting a Completed `Step` -In the case of a restartable job, there may be one or more steps - that should always be run, regardless of whether or not they were - successful the first time. An example might be a validation step or a - `Step` that cleans up resources before - processing. During normal processing of a restarted job, any step with - a status of 'COMPLETED', meaning it has already been completed - successfully, is skipped. Setting `allow-start-if-complete` to - "true" overrides this so that the step always runs, as shown in the following example: +In the case of a restartable job, there may be one or more steps that should always be +run, regardless of whether or not they were successful the first time. An example might +be a validation step or a `Step` that cleans up resources before processing. During +normal processing of a restarted job, any step with a status of 'COMPLETED', meaning it +has already been completed successfully, is skipped. Setting `allow-start-if-complete` to +"true" overrides this so that the step always runs, as shown in the following example: .XML Configuration [source, xml, role="xmlContent"] @@ -496,8 +408,6 @@ public Step step1() { ---- [[stepRestartExample]] - - ===== `Step` Restart Configuration Example The following example shows how to configure a job to have steps that can be restarted: @@ -570,37 +480,29 @@ public Step playerSummarization() { } ---- -The preceding example configuration is for a job that loads in - information about football games and summarizes them. It contains - three steps: `playerLoad`, `gameLoad`, and `playerSummarization`. The - playerLoad `Step` loads player information from a - flat file, while the gameLoad `Step` does the - same for games. The final `Step`, - `playerSummarization`, then summarizes the statistics for each player, - based upon the provided games. It is assumed that the file loaded by - 'playerLoad' must be loaded only once, but that 'gameLoad' can load - any games found within a particular directory, deleting them after - they have been successfully loaded into the database. As a result, the - playerLoad `Step` contains no additional - configuration. It can be started any number of times, and, if complete, - is skipped. The 'gameLoad' `Step`, however, - needs to be run every time in case extra files have been added since - it last ran. It has 'allow-start-if-complete' set to 'true' in - order to always be started. (It is assumed that the database tables - games are loaded into has a process indicator on it, to ensure new - games can be properly found by the summarization step). The - summarization `Step`, which is the most important - in the `Job`, is configured to have a start limit - of 3. This is useful because if the step continually fails, a new exit - code is returned to the operators that control job execution, and - it can not start again until manual intervention has taken - place. - +The preceding example configuration is for a job that loads in information about football +games and summarizes them. It contains three steps: `playerLoad`, `gameLoad`, and +`playerSummarization`. The playerLoad `Step` loads player information from a flat file, +while the gameLoad `Step` does the same for games. The final `Step`, +`playerSummarization`, then summarizes the statistics for each player, based upon the +provided games. It is assumed that the file loaded by 'playerLoad' must be loaded only +once, but that 'gameLoad' can load any games found within a particular directory, +deleting them after they have been successfully loaded into the database. As a result, +the playerLoad `Step` contains no additional configuration. It can be started any number +of times, and, if complete, is skipped. The 'gameLoad' `Step`, however, needs to be run +every time in case extra files have been added since it last ran. It has +'allow-start-if-complete' set to 'true' in order to always be started. (It is assumed +that the database tables games are loaded into has a process indicator on it, to ensure +new games can be properly found by the summarization step). The summarization `Step`, +which is the most important in the `Job`, is configured to have a start limit of 3. This +is useful because if the step continually fails, a new exit code is returned to the +operators that control job execution, and it can not start again until manual +intervention has taken place. [NOTE] ==== -This job provides an example for this document and is not the same as - the `footballJob` found in the samples project. +This job provides an example for this document and is not the same as the `footballJob` +found in the samples project. ==== The remainder of this section describes what happens for each of three runs of the @@ -608,70 +510,43 @@ The remainder of this section describes what happens for each of three runs of t Run 1: - -. `playerLoad` runs and completes successfully, adding - 400 players to the 'PLAYERS' table. - - -. `gameLoad` runs and processes 11 files worth of game - data, loading their contents into the 'GAMES' table. - - -. `playerSummarization` begins processing and fails after 5 - minutes. +. `playerLoad` runs and completes successfully, adding 400 players to the 'PLAYERS' +table. +. `gameLoad` runs and processes 11 files worth of game data, loading their contents +into the 'GAMES' table. +. `playerSummarization` begins processing and fails after 5 minutes. Run 2: - -. `playerLoad` does not run, since it has already completed - successfully, and `allow-start-if-complete` is 'false' (the - default). - - -. `gameLoad` runs again and processes another 2 files, - loading their contents into the 'GAMES' table as well (with a - process indicator indicating they have yet to be processed) - - -. `playerSummarization` begins processing of all remaining game - data (filtering using the process indicator) and fails again after - 30 minutes. +. `playerLoad` does not run, since it has already completed successfully, and +`allow-start-if-complete` is 'false' (the default). +. `gameLoad` runs again and processes another 2 files, loading their contents into the +'GAMES' table as well (with a process indicator indicating they have yet to be +processed). +. `playerSummarization` begins processing of all remaining game data (filtering using the +process indicator) and fails again after 30 minutes. Run 3: - - -. `playerLoad` does not run, since it has already completed - successfully, and `allow-start-if-complete` is 'false' (the - default). - - -. `gameLoad` runs again and processes another 2 files, - loading their contents into the 'GAMES' table as well (with a - process indicator indicating they have yet to be processed) - - -. `playerSummarization` is not started and the job is immediately - killed, since this is the third execution of playerSummarization, - and its limit is only 2. Either the limit must be raised or the - `Job` must be executed as a new - `JobInstance`. +. `playerLoad` does not run, since it has already completed successfully, and +`allow-start-if-complete` is 'false' (the default). +. `gameLoad` runs again and processes another 2 files, loading their contents into the +'GAMES' table as well (with a process indicator indicating they have yet to be +processed). +. `playerSummarization` is not started and the job is immediately killed, since this is +the third execution of playerSummarization, and its limit is only 2. Either the limit +must be raised or the `Job` must be executed as a new `JobInstance`. [[configuringSkip]] - - ==== Configuring Skip Logic -There are many scenarios where errors encountered while processing - should not result in `Step` failure, but should be - skipped instead. This is usually a decision that must be made by someone - who understands the data itself and what meaning it has. Financial data, - for example, may not be skippable because it results in money being - transferred, which needs to be completely accurate. Loading a list of - vendors, on the other hand, might allow for skips. If a vendor is not - loaded because it was formatted incorrectly or was missing necessary - information, then there probably are not issues. Usually, these bad - records are logged as well, which is covered later when discussing - listeners. +There are many scenarios where errors encountered while processing should not result in +`Step` failure, but should be skipped instead. This is usually a decision that must be +made by someone who understands the data itself and what meaning it has. Financial data, +for example, may not be skippable because it results in money being transferred, which +needs to be completely accurate. Loading a list of vendors, on the other hand, might +allow for skips. If a vendor is not loaded because it was formatted incorrectly or was +missing necessary information, then there probably are not issues. Usually, these bad +records are logged as well, which is covered later when discussing listeners. The following example shows an example of using a skip limit: @@ -707,21 +582,18 @@ public Step step1() { ---- -In the preceding example, a `FlatFileItemReader` is - used. If, at any point, a - `FlatFileParseException` is thrown, the item is - skipped and counted against the total skip limit of 10. Separate counts - are made of skips on read, process, and write inside the step execution, - but the limit applies across all skips. Once the skip limit is reached, the - next exception found causes the step to fail. In other words, the eleventh skip - triggers the exception, not the tenth. +In the preceding example, a `FlatFileItemReader` is used. If, at any point, a +`FlatFileParseException` is thrown, the item is skipped and counted against the total +skip limit of 10. Separate counts are made of skips on read, process, and write inside +the step execution, but the limit applies across all skips. Once the skip limit is +reached, the next exception found causes the step to fail. In other words, the eleventh +skip triggers the exception, not the tenth. -One problem with the preceding example is that any other exception - besides a `FlatFileParseException` causes 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, as shown in the following example: +One problem with the preceding example is that any other exception besides a +`FlatFileParseException` causes 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, as shown in the following +example: .XML Configuration [source, xml, role="xmlContent"] @@ -756,53 +628,38 @@ public Step step1() { } ---- -By identifying `java.lang.Exception` as a - skippable exception class, the configuration indicates that all - `Exceptions` are skippable. However, by 'excluding' - `java.io.FileNotFoundException`, the configuration - refines the list of skippable exception classes to be all - `Exceptions` __except__ - `FileNotFoundException`. Any excluded exception - classes will be fatal if encountered (that is, they are not skipped). +By identifying `java.lang.Exception` as a skippable exception class, the configuration +indicates that all `Exceptions` are skippable. However, by 'excluding' +`java.io.FileNotFoundException`, the configuration refines the list of skippable +exception classes to be all `Exceptions` __except__ `FileNotFoundException`. Any excluded +exception classes is fatal if encountered (that is, they are not skipped). -For any exception encountered, the skippability is determined - by the nearest superclass in the class hierarchy. Any unclassifed - exception is treated as 'fatal'. +For any exception encountered, the skippability is determined by the nearest superclass +in the class hierarchy. Any unclassifed exception is treated as 'fatal'. ifdef::backend-html5[] [role="xmlContent"] -The order of the - `` and `` elements - does not matter. +The order of the `` and `` elements does not matter. [role="javaContent"] -The order of the - `skip` and `noSkip` calls - does not matter. +The order of the `skip` and `noSkip` calls does not matter. endif::backend-html5[] ifdef::backend-pdf[] -The order of specifying include vs exclude (either via the XML tags or `skip` and `noSkip` -method calls) does not matter. +The order of specifying include vs exclude (by using either the XML tags or `skip` and +`noSkip` method calls) does not matter. endif::backend-pdf[] - [[retryLogic]] - - ==== Configuring Retry Logic -In most cases, you want an exception to cause either a skip or a - `Step` failure. However, not all exceptions are - deterministic. If a `FlatFileParseException` is - encountered while reading, it is always thrown for that record. - Resetting the `ItemReader` does not help. However, - for other exceptions, such as a - `DeadlockLoserDataAccessException`, which indicates - that the current process has attempted to update a record that another - process holds a lock on. Waiting and trying again might result in - success. In this case, retry should be configured as follows: - +In most cases, you want an exception to cause either a skip or a `Step` failure. However, +not all exceptions are deterministic. If a `FlatFileParseException` is encountered while +reading, it is always thrown for that record. Resetting the `ItemReader` does not help. +However, for other exceptions, such as a `DeadlockLoserDataAccessException`, which +indicates that the current process has attempted to update a record that another process +holds a lock on. Waiting and trying again might result in success. In this case, retry +should be configured as follows: [source, xml, role="xmlContent"] ---- @@ -833,25 +690,20 @@ public Step step1() { } ---- -The `Step` allows a limit for the number of - times an individual item can be retried and a list of exceptions that - are 'retryable'. More details on how retry works can be found in <>. +The `Step` allows a limit for the number of times an individual item can be retried and a +list of exceptions that are 'retryable'. More details on how retry works can be found in +<>. [[controllingRollback]] - - ==== Controlling Rollback -By default, regardless of retry or skip, any exceptions thrown - from the `ItemWriter` cause the transaction - controlled by the `Step` to rollback. If skip is - configured as described above, exceptions thrown from the - `ItemReader` do not cause a rollback. However, - there are many scenarios in which exceptions thrown from the - `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, as shown in the following example: +By default, regardless of retry or skip, any exceptions thrown from the `ItemWriter` +cause the transaction controlled by the `Step` to rollback. If skip is configured as +described earlier, exceptions thrown from the `ItemReader` do not cause a rollback. +However, there are many scenarios in which exceptions thrown from the `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, as shown in the following example: .XML Configuration [source, xml, role="xmlContent"] @@ -882,19 +734,15 @@ public Step step1() { ---- [[transactionalReaders]] - - ===== Transactional Readers -The basic contract of the `ItemReader` is - that it is forward only. The step buffers reader input, so that, in the - case of a rollback, the items do not need to be re-read from the reader. - However, there are certain scenarios in which the reader is built on - top of a transactional resource, such as a JMS queue. In this case, - since the queue is tied to the transaction that is rolled back, the - messages that have been pulled from the queue are put back on. For - this reason, the step can be configured to not buffer the - items, as shown in the following example: +The basic contract of the `ItemReader` is that it is forward only. The step buffers +reader input, so that, in the case of a rollback, the items do not need to be re-read +from the reader. However, there are certain scenarios in which the reader is built on +top of a transactional resource, such as a JMS queue. In this case, since the queue is +tied to the transaction that is rolled back, the messages that have been pulled from the +queue are put back on. For this reason, the step can be configured to not buffer the +items, as shown in the following example: .XML Configuration [source, xml, role="xmlContent"] @@ -922,13 +770,14 @@ public Step step1() { ---- [[transactionAttributes]] - ==== Transaction Attributes -Transaction attributes can be used to control the `isolation`, - `propagation`, and `timeout` settings. More information on setting - transaction attributes can be found in the https://docs.spring.io/spring/docs/current/spring-framework-reference/data-access.html#transaction[Spring core - documentation]. The following example sets the `isolation`, `propagation`, and `timeout` transaction attributes: +Transaction attributes can be used to control the `isolation`, `propagation`, and +`timeout` settings. More information on setting transaction attributes can be found in +the +https://docs.spring.io/spring/docs/current/spring-framework-reference/data-access.html#transaction[Spring +core documentation]. The following example sets the `isolation`, `propagation`, and +`timeout` transaction attributes: .XML Configuration [source, xml, role="xmlContent"] @@ -963,27 +812,19 @@ public Step step1() { ---- [[registeringItemStreams]] - - ==== Registering `ItemStream` with a `Step` -The step has to take care of `ItemStream` - callbacks at the necessary points in its lifecycle. (For more - information on the `ItemStream` interface, - see <>) This is vital if a step fails - and might need to be restarted, because the - `ItemStream` interface is where the step gets the - information it needs about persistent state between executions. +The step has to take care of `ItemStream` callbacks at the necessary points in its +lifecycle. (For more information on the `ItemStream` interface, see +<>) This is vital if a step fails and might +need to be restarted, because the `ItemStream` interface is where the step gets the +information it needs about persistent state between executions. -If the `ItemReader`, - `ItemProcessor`, or - `ItemWriter` itself implements the - `ItemStream` interface, then these are - registered automatically. Any other streams need to be registered - separately. This is often the case where indirect dependencies - such as delegates are injected into the reader and writer. A stream - can be registered on the `Step` through the - 'streams' element, as illustrated in the following example: +If the `ItemReader`, `ItemProcessor`, or `ItemWriter` itself implements the `ItemStream` +interface, then these are registered automatically. Any other streams need to be +registered separately. This is often the case where indirect dependencies, such as +delegates, are injected into the reader and writer. A stream can be registered on the +`Step` through the 'streams' element, as illustrated in the following example: .XML Configuration [source, xml, role="xmlContent"] @@ -1042,42 +883,29 @@ public CompositeItemWriter compositeItemWriter() { } ---- -In the example above, the - `CompositeItemWriter` is not an - `ItemStream`, but both of its delegates are. - Therefore, both delegate writers must be explicitly registered as - streams in order for the framework to handle them correctly. The - `ItemReader` does not need to be explicitly - registered as a stream because it is a direct property of the - `Step`. The step is now restartable, and the - state of the reader and writer is correctly persisted in the event - of a failure. +In the example above, the `CompositeItemWriter` is not an `ItemStream`, but both of its +delegates are. Therefore, both delegate writers must be explicitly registered as streams +in order for the framework to handle them correctly. The `ItemReader` does not need to be +explicitly registered as a stream because it is a direct property of the `Step`. The step +is now restartable, and the state of the reader and writer is correctly persisted in the +event of a failure. [[interceptingStepExecution]] - - ==== Intercepting `Step` Execution -Just as with the `Job`, there are many events - during the execution of a `Step` where a user may - need to perform some functionality. For example, in order to write out - to a flat file that requires a footer, the - `ItemWriter` needs to be notified when the - `Step` has been completed, so that the footer can - written. This can be accomplished with one of many - `Step` scoped listeners. +Just as with the `Job`, there are many events during the execution of a `Step` where a +user may need to perform some functionality. For example, in order to write out to a flat +file that requires a footer, the `ItemWriter` needs to be notified when the `Step` has +been completed, so that the footer can written. This can be accomplished with one of many +`Step` scoped listeners. -Any class that implements one of the extensions - of `StepListener` (but not that interface - itself since it is empty) can be applied to a step through the - `listeners` element. The `listeners` element is valid inside a - step, tasklet, or chunk declaration. It is recommended that you - declare the listeners at the level at which its function applies, - or, if it is multi-featured - (such as `StepExecutionListener` - and `ItemReadListener`), then declare it at - the most granular level where it applies. - The following example shows a listener applied at the chunk level: +Any class that implements one of the extensions of `StepListener` (but not that interface +itself since it is empty) can be applied to a step through the `listeners` element. +The `listeners` element is valid inside a step, tasklet, or chunk declaration. It is +recommended that you declare the listeners at the level at which its function applies, +or, if it is multi-featured (such as `StepExecutionListener` and `ItemReadListener`), +then declare it at the most granular level where it applies. The following example shows +a listener applied at the chunk level: .XML Configuration [source, xml, role="xmlContent"] @@ -1106,39 +934,27 @@ public Step step1() { } ---- -An `ItemReader`, - `ItemWriter` or - `ItemProcessor` that itself implements one of the - `StepListener` interfaces is registered - automatically with the `Step` if using the - namespace `` element or one of the the - `*StepFactoryBean` factories. This only applies to - components directly injected into the `Step`. If - the listener is nested inside another component, it needs to be - explicitly registered (as described previously under <>). +An `ItemReader`, `ItemWriter` or `ItemProcessor` that itself implements one of the +`StepListener` interfaces is registered automatically with the `Step` if using the +namespace `` element or one of the the `*StepFactoryBean` factories. This only +applies to components directly injected into the `Step`. If the listener is nested inside +another component, it needs to be explicitly registered (as described previously under +<>). -In addition to the `StepListener` interfaces, - annotations are provided to address the same concerns. Plain old Java - objects can have methods with these annotations that are then converted - into the corresponding `StepListener` type. It is - also common to annotate custom implementations of chunk components such as - `ItemReader` or `ItemWriter` - or `Tasklet`. The annotations are analyzed by the - XML parser for the `` elements as well as registered via the `listener` - methods in the builders, so all you - need to do is use the XML namespace or builders to register the listeners with a - step. +In addition to the `StepListener` interfaces, annotations are provided to address the +same concerns. Plain old Java objects can have methods with these annotations that are +then converted into the corresponding `StepListener` type. It is also common to annotate +custom implementations of chunk components such as `ItemReader` or `ItemWriter` or +`Tasklet`. The annotations are analyzed by the XML parser for the `` elements +as well as registered with the `listener` methods in the builders, so all you need to do +is use the XML namespace or builders to register the listeners with a step. [[stepExecutionListener]] - - ===== `StepExecutionListener` -`StepExecutionListener` represents the most - generic listener for `Step` execution. It allows - for notification before a `Step` is started and - after it ends, whether it ended normally or failed, as shown in the following example: - +`StepExecutionListener` represents the most generic listener for `Step` execution. It +allows for notification before a `Step` is started and after it ends, whether it ended +normally or failed, as shown in the following example: [source, java] ---- @@ -1151,30 +967,21 @@ public interface StepExecutionListener extends StepListener { } ---- -`ExitStatus` is the return type of - `afterStep` in order to allow listeners the - chance to modify the exit code that is returned upon completion of a - `Step`. +`ExitStatus` is the return type of `afterStep` in order to allow listeners the chance to +modify the exit code that is returned upon completion of a `Step`. The annotations corresponding to this interface are: - * `@BeforeStep` - - * `@AfterStep` [[chunkListener]] - - ===== `ChunkListener` -A chunk is defined as the items processed within the scope of a - transaction. Committing a transaction, at each commit interval, - commits a 'chunk'. A `ChunkListener` can be - used to perform logic before a chunk begins processing or after a - chunk has completed successfully, as shown in the following interface definition: - +A chunk is defined as the items processed within the scope of a transaction. Committing a +transaction, at each commit interval, commits a 'chunk'. A `ChunkListener` can be used to +perform logic before a chunk begins processing or after a chunk has completed +successfully, as shown in the following interface definition: [source, java] ---- @@ -1186,38 +993,26 @@ public interface ChunkListener extends StepListener { } ---- -The beforeChunk method is called after - the transaction is started but before read - is called on the `ItemReader`. Conversely, - `afterChunk` is called after the chunk has been - committed (and not at all if there is a rollback). +The beforeChunk method is called after the transaction is started but before read is +called on the `ItemReader`. Conversely, `afterChunk` is called after the chunk has been +committed (and not at all if there is a rollback). The annotations corresponding to this interface are: - * `@BeforeChunk` - - * `@AfterChunk` -A `ChunkListener` can be applied - when there is no chunk declaration. - The `TaskletStep` is responsible for - calling the `ChunkListener`, so it applies - to a non-item-oriented tasklet as well (it is called before and - after the tasklet). +A `ChunkListener` can be applied when there is no chunk declaration. The `TaskletStep` is +responsible for calling the `ChunkListener`, so it applies to a non-item-oriented tasklet +as well (it is called before and after the tasklet). [[itemReadListener]] - - ===== `ItemReadListener` -When discussing skip logic previously, it was mentioned that it may - be beneficial to log the skipped records, so that they can be dealt - with later. In the case of read errors, this can be done with an - `ItemReaderListener`, as shown in the following interface definition: - - +When discussing skip logic previously, it was mentioned that it may be beneficial to log +the skipped records, so that they can be dealt with later. In the case of read errors, +this can be done with an `ItemReaderListener`, as shown in the following interface +definition: [source, java] ---- @@ -1230,35 +1025,22 @@ public interface ItemReadListener extends StepListener { } ---- -The `beforeRead` method is called - before each call to read on the - `ItemReader`. The - `afterRead` method is called after each - successful call to read and is passed - the item that was read. If there was an error while reading, the - `onReadError` method is called. The - exception encountered is provided so that it can be - logged. +The `beforeRead` method is called before each call to read on the `ItemReader`. The +`afterRead` method is called after each successful call to read and is passed the item +that was read. If there was an error while reading, the `onReadError` method is called. +The exception encountered is provided so that it can be logged. The annotations corresponding to this interface are: - * `@BeforeRead` - - * `@AfterRead` - - * `@OnReadError` [[itemProcessListener]] - - ===== `ItemProcessListener` -Just as with the `ItemReadListener`, the - processing of an item can be 'listened' to, as shown in the following interface definition: - +Just as with the `ItemReadListener`, the processing of an item can be 'listened' to, as +shown in the following interface definition: [source, java] ---- @@ -1271,35 +1053,23 @@ public interface ItemProcessListener extends StepListener { } ---- -The `beforeProcess` method is called - before `process` on the - `ItemProcessor` and is handed the item that is to - be processed. The `afterProcess` method is - called after the item has been successfully processed. If there was an - error while processing, the `onProcessError` - method is called. The exception encountered and the item that was - attempted to be processed is provided, so that they can be - logged. +The `beforeProcess` method is called before `process` on the `ItemProcessor` and is +handed the item that is to be processed. The `afterProcess` method is called after the +item has been successfully processed. If there was an error while processing, the +`onProcessError` method is called. The exception encountered and the item that was +attempted to be processed is provided, so that they can be logged. The annotations corresponding to this interface are: - * `@BeforeProcess` - - * `@AfterProcess` - - * `@OnProcessError` [[itemWriteListener]] - - ===== `ItemWriteListener` -The writing of an item can be 'listened' to with the - `ItemWriteListener`, as shown in the following interface definition: - +The writing of an item can be 'listened' to with the `ItemWriteListener`, as shown in the +following interface definition: [source, java] ---- @@ -1312,40 +1082,26 @@ public interface ItemWriteListener extends StepListener { } ---- -The `beforeWrite` method is called - before `write` on the - `ItemWriter` and is handed the list of items that is - written. The `afterWrite` method is called - after the item has been successfully written. If there was an error - while writing, the `onWriteError` method is - called. The exception encountered and the item that was attempted - to be written is provided, so that they can be logged. +The `beforeWrite` method is called before `write` on the `ItemWriter` and is handed the +list of items that is written. The `afterWrite` method is called after the item has been +successfully written. If there was an error while writing, the `onWriteError` method is +called. The exception encountered and the item that was attempted to be written is +provided, so that they can be logged. The annotations corresponding to this interface are: - * `@BeforeWrite` - - * `@AfterWrite` - - * `@OnWriteError` [[skipListener]] - - ===== `SkipListener` -`ItemReadListener`, - `ItemProcessListener`, and - `ItemWriteListener` all provide mechanisms for - being notified of errors, but none informs you that a record has - actually been skipped. `onWriteError`, for - example, is called even if an item is retried and successful. For - this reason, there is a separate interface for tracking skipped - items, as shown in the following interface definition: - +`ItemReadListener`, `ItemProcessListener`, and `ItemWriteListener` all provide mechanisms +for being notified of errors, but none informs you that a record has actually been +skipped. `onWriteError`, for example, is called even if an item is retried and +successful. For this reason, there is a separate interface for tracking skipped items, as +shown in the following interface definition: [source, java] ---- @@ -1358,68 +1114,46 @@ public interface SkipListener extends StepListener { } ---- -`onSkipInRead` is called whenever an - item is skipped while reading. It should be noted that rollbacks may - cause the same item to be registered as skipped more than once. - `onSkipInWrite` is called when an item is - skipped while writing. Because the item has been read successfully - (and not skipped), it is also provided the item itself as an - argument. +`onSkipInRead` is called whenever an item is skipped while reading. It should be noted +that rollbacks may cause the same item to be registered as skipped more than once. +`onSkipInWrite` is called when an item is skipped while writing. Because the item has +been read successfully (and not skipped), it is also provided the item itself as an +argument. The annotations corresponding to this interface are: - * `@OnSkipInRead` - - * `@OnSkipInWrite` - - * `@OnSkipInProcess` [[skipListenersAndTransactions]] - - ====== SkipListeners and Transactions -One of the most common use cases for a - `SkipListener` is to log out a skipped item, so - that another batch process or even human process can be used to - evaluate and fix the issue leading to the skip. Because there are - many cases in which the original transaction may be rolled back, - Spring Batch makes two guarantees: +One of the most common use cases for a `SkipListener` is to log out a skipped item, so +that another batch process or even human process can be used to evaluate and fix the +issue leading to the skip. Because there are many cases in which the original transaction +may be rolled back, Spring Batch makes two guarantees: - -. The appropriate skip method (depending on when the error - happened) is called only once per item. - - -. The `SkipListener` is always - called just before the transaction is committed. This is to - ensure that any transactional resources call by the listener are - not rolled back by a failure within the - `ItemWriter`. +. The appropriate skip method (depending on when the error happened) is called only once +per item. +. The `SkipListener` is always called just before the transaction is committed. This is +to ensure that any transactional resources call by the listener are not rolled back by a +failure within the `ItemWriter`. [[taskletStep]] - - === `TaskletStep` <> is not the only way to process in a - `Step`. What if a `Step` must - consist of a simple stored procedure call? You could implement the call as - an `ItemReader` and return null after the procedure - finishes. However, doing so is a bit unnatural, since there would need to be a no-op - `ItemWriter`. Spring Batch provides the - `TaskletStep` for this scenario. +`Step`. What if a `Step` must consist of a simple stored procedure call? You could +implement the call as an `ItemReader` and return null after the procedure finishes. +However, doing so is a bit unnatural, since there would need to be a no-op `ItemWriter`. +Spring Batch provides the `TaskletStep` for this scenario. -`Tasklet` is a simple interface that has - one method, `execute`, which is called - repeatedly by the `TaskletStep` until it either - returns `RepeatStatus.FINISHED` or throws an exception to - signal a failure. Each call to a `Tasklet` is - wrapped in a transaction. `Tasklet` implementors - might call a stored procedure, a script, or a simple SQL update statement. +`Tasklet` is a simple interface that has one method, `execute`, which is called +repeatedly by the `TaskletStep` until it either returns `RepeatStatus.FINISHED` or throws +an exception to signal a failure. Each call to a `Tasklet` is wrapped in a transaction. +`Tasklet` implementors might call a stored procedure, a script, or a simple SQL update +statement. ifdef::backend-html5[] [role="xmlContent"] @@ -1452,10 +1186,10 @@ public Step step1() { endif::backend-html5[] ifdef::backend-pdf[] -To create a `TaskletStep` the bean associated with the step (via the `ref` attribute when -using the namespace or passed to the `tasklet` method when using java config), should be -a bean that implements the interface `Tasklet`. The following example shows a simple -tasklet: +To create a `TaskletStep` the bean associated with the step (through the `ref` attribute +when using the namespace or passed to the `tasklet` method when using java config), +should be a bean that implements the interface `Tasklet`. The following example shows a +simple `tasklet`: .XML Configuration [source, xml] @@ -1482,24 +1216,17 @@ endif::backend-pdf[] `TaskletStep` automatically registers the tasklet as a `StepListener` if it implements the `StepListener` interface. - ==== - [[taskletAdapter]] - - ==== `TaskletAdapter` -As with other adapters for the `ItemReader` - and `ItemWriter` interfaces, the - `Tasklet` interface contains an implementation that - allows for adapting itself to any pre-existing class: - `TaskletAdapter`. An example where this may be - useful is an existing DAO that is used to update a flag on a set of - records. The `TaskletAdapter` can be used to call - this class without having to write an adapter for the - `Tasklet` interface, as shown in the following example: +As with other adapters for the `ItemReader` and `ItemWriter` interfaces, the `Tasklet` +interface contains an implementation that allows for adapting itself to any pre-existing +class: `TaskletAdapter`. An example where this may be useful is an existing DAO that is +used to update a flag on a set of records. The `TaskletAdapter` can be used to call this +class without having to write an adapter for the `Tasklet` interface, as shown in the +following example: .XML Configuration [source, xml, role="xmlContent"] @@ -1527,19 +1254,15 @@ public MethodInvokingTaskletAdapter myTasklet() { ---- [[exampleTaskletImplementation]] - - ==== Example `Tasklet` Implementation -Many batch jobs contain steps that must be done before the main - processing begins in order to set up various resources or after - processing has completed to cleanup those resources. In the case of a - job that works heavily with files, it is often necessary to delete - certain files locally after they have been uploaded successfully to - another location. The following example (taken from the https://github.com/spring-projects/spring-batch/tree/master/spring-batch-samples[Spring Batch samples - project]) is a `Tasklet` implementation with just - such a responsibility: - +Many batch jobs contain steps that must be done before the main processing begins in +order to set up various resources or after processing has completed to cleanup those +resources. In the case of a job that works heavily with files, it is often necessary to +delete certain files locally after they have been uploaded successfully to another +location. The following example (taken from the +https://github.com/spring-projects/spring-batch/tree/master/spring-batch-samples[Spring +Batch samples project]) is a `Tasklet` implementation with just such a responsibility: [source, java] ---- @@ -1573,12 +1296,9 @@ public class FileDeletingTasklet implements Tasklet, InitializingBean { } ---- -The preceding `Tasklet` implementation - deletes all files within a given directory. It should be noted that the - `execute` method is called only once. All - that is left is to reference the `Tasklet` from the - `Step`: - +The preceding `Tasklet` implementation deletes all files within a given directory. It +should be noted that the `execute` method is called only once. All that is left is to +reference the `Tasklet` from the `Step`: .XML Configuration [source, xml, role="xmlContent"] @@ -1629,32 +1349,25 @@ public FileDeletingTasklet fileDeletingTasklet() { ---- [[controllingStepFlow]] - - === Controlling Step Flow -With the ability to group steps together within an owning job comes - the need to be able to control how the job "flows" from one step to - another. The failure of a `Step` does not necessarily - mean that the `Job` should fail. Furthermore, there - may be more than one type of 'success' that determines which - `Step` should be executed next. Depending upon how a - group of `Steps` is configured, certain steps may not even be processed at - all. +With the ability to group steps together within an owning job comes the need to be able +to control how the job "flows" from one step to another. The failure of a `Step` does not +necessarily mean that the `Job` should fail. Furthermore, there may be more than one type +of 'success' that determines which `Step` should be executed next. Depending upon how a +group of `Steps` is configured, certain steps may not even be processed at all. [[SequentialFlow]] - - ==== Sequential Flow -The simplest flow scenario is a job where all of the steps execute - sequentially, as shown in the following image: +The simplest flow scenario is a job where all of the steps execute sequentially, as shown +in the following image: .Sequential Flow image::{batch-asciidoc}images/sequential-flow.png[Sequential Flow, scaledwidth="60%"] -This can be achieved by using the 'next' attribute of the step - element, as shown in the following example: +This can be achieved by using the 'next' attribute of the step element, as shown in the +following example: .XML Configuration [source, xml, role="xmlContent"] @@ -1679,12 +1392,9 @@ public Job job() { } ---- -In the scenario above, 'step A' runs - first because it is the first `Step` listed. If - 'step A' completes normally, then 'step B' runs, and so on. - However, if 'step A' fails, then the entire `Job` - fails and 'step B' does not execute. - +In the scenario above, 'step A' runs first because it is the first `Step` listed. If +'step A' completes normally, then 'step B' runs, and so on. However, if 'step A' fails, +then the entire `Job` fails and 'step B' does not execute. [role="xmlContent"] [NOTE] @@ -1696,45 +1406,33 @@ With the Spring Batch namespace, the first step listed in the first in the xml. ==== - [[conditionalFlow]] - - ==== Conditional Flow In the example above, there are only two possibilities: +. The `Step` is successful and the next `Step` should be executed. +. The `Step` failed and, thus, the `Job` should fail. -. The `Step` is successful and the next - `Step` should be executed. - - -. The `Step` failed and, thus, the - `Job` should fail. - -In many cases, this may be sufficient. However, what about a - scenario in which the failure of a `Step` should - trigger a different `Step`, rather than causing - failure? The following image shows such a flow: +In many cases, this may be sufficient. However, what about a scenario in which the +failure of a `Step` should trigger a different `Step`, rather than causing failure? The +following image shows such a flow: .Conditional Flow image::{batch-asciidoc}images/conditional-flow.png[Conditional Flow, scaledwidth="60%"] [[nextElement]] -In order to handle more complex scenarios, the - Spring Batch namespace allows transition elements to be defined within - the step element. One such transition is the `next` element. Like the - `next` attribute, the `next` element tells the - `Job` which `Step` to execute - next. However, unlike the attribute, any number of `next` elements are - allowed on a given `Step`, and there is no default - behavior the case of failure. This means that, if transition elements are - used, then all of the behavior for the `Step` - transitions must be defined explicitly. Note also that a single step - cannot have both a `next` attribute and a `transition` element. +In order to handle more complex scenarios, the Spring Batch namespace allows transition +elements to be defined within the step element. One such transition is the `next` +element. Like the `next` attribute, the `next` element tells the `Job` which `Step` to +execute next. However, unlike the attribute, any number of `next` elements are allowed on +a given `Step`, and there is no default behavior the case of failure. This means that, if +transition elements are used, then all of the behavior for the `Step` transitions must be +defined explicitly. Note also that a single step cannot have both a `next` attribute and +a `transition` element. -The `next` element specifies a pattern to match and the step to - execute next, as shown in the following example: +The `next` element specifies a pattern to match and the step to execute next, as shown in +the following example: .XML Configuration [source, xml, role="xmlContent"] @@ -1765,58 +1463,43 @@ public Job job() { [role="xmlContent"] When using XML configuration, the `on` attribute of a transition element uses a simple - pattern-matching scheme to match the `ExitStatus` - that results from the execution of the `Step`. +pattern-matching scheme to match the `ExitStatus` that results from the execution of the +`Step`. [role="javaContent"] -When using java configuration the `on` method uses a simple - pattern-matching scheme to match the `ExitStatus` - that results from the execution of the `Step`. +When using java configuration the `on` method uses a simple pattern-matching scheme to +match the `ExitStatus` that results from the execution of the `Step`. Only two special characters are allowed in the pattern: +* "*" matches zero or more characters +* "?" matches exactly one character -* "*" will zero or more characters +For example, "c*t" matches "cat" and "count", while "c?t" matches "cat" but not "count". - -* "?" will match exactly one character - -For example, "c*t" matches "cat" and "count", while "c?t" - matches "cat" but not "count". - -While there is no limit to the number of transition elements on a - `Step`, if the `Step` - execution results in an `ExitStatus` that is not - covered by an element, then the framework throws an exception and - the `Job` fails. The framework - automatically orders transitions from most specific to - least specific. This means that, even if the ordering were swapped for - "stepA" in the example above, an `ExitStatus` of - "FAILED" would still go to "stepC". +While there is no limit to the number of transition elements on a `Step`, if the `Step` +execution results in an `ExitStatus` that is not covered by an element, then the +framework throws an exception and the `Job` fails. The framework automatically orders +transitions from most specific to least specific. This means that, even if the ordering +were swapped for "stepA" in the example above, an `ExitStatus` of "FAILED" would still go +to "stepC". [[batchStatusVsExitStatus]] - - ===== Batch Status Versus Exit Status -When configuring a `Job` for conditional - flow, it is important to understand the difference between - `BatchStatus` and - `ExitStatus`. `BatchStatus` - is an enumeration that is a property of both - `JobExecution` and - `StepExecution` and is used by the framework to - record the status of a `Job` or - `Step`. It can be one of the following values: - `COMPLETED`, `STARTING`, `STARTED`, `STOPPING`, `STOPPED`, `FAILED`, `ABANDONED`, or - `UNKNOWN`. Most of them are self explanatory: `COMPLETED` is the status - set when a step or job has completed successfully, `FAILED` is set when - it fails, and so on. +When configuring a `Job` for conditional flow, it is important to understand the +difference between `BatchStatus` and `ExitStatus`. `BatchStatus` is an enumeration that +is a property of both `JobExecution` and `StepExecution` and is used by the framework to +record the status of a `Job` or `Step`. It can be one of the following values: +`COMPLETED`, `STARTING`, `STARTED`, `STOPPING`, `STOPPED`, `FAILED`, `ABANDONED`, or +`UNKNOWN`. Most of them are self explanatory: `COMPLETED` is the status set when a step +or job has completed successfully, `FAILED` is set when it fails, and so on. [role="xmlContent"] The following example contains the 'next' element when using XML configuration: // TODO It might help readers to know the difference between STARTING and STARTED (same -// for STOPPING and STOPPED). Specifically, when does the status go from STARTING to STARTED? +// for STOPPING and STOPPED). Specifically, when does the status go from STARTING to +// STARTED? [source, xml, role="xmlContent"] ---- @@ -1833,29 +1516,22 @@ The following example contains the 'on' element when using Java Configuration: ... ---- -At first glance, it would appear that 'on' - references the `BatchStatus` of the - `Step` to which it belongs. However, it actually - references the `ExitStatus` of the - `Step`. As the name implies, - `ExitStatus` represents the status of a - `Step` after it finishes execution. +At first glance, it would appear that 'on' references the `BatchStatus` of the `Step` to +which it belongs. However, it actually references the `ExitStatus` of the `Step`. As the +name implies, `ExitStatus` represents the status of a `Step` after it finishes execution. [role="xmlContent"] -More specifically, when using XML configuration, the 'next' element shown in the preceding -XML configuration example references the exit code of `ExitStatus`. +More specifically, when using XML configuration, the 'next' element shown in the +preceding XML configuration example references the exit code of `ExitStatus`. [role="xmlContent"] When using Java configuration, the 'on' method shown in the preceding Java configuration example references the exit code of `ExitStatus`. - -In English, it says: - "go to stepB if the exit code is `FAILED`". By default, the exit code is - always the same as the `BatchStatus` for the - `Step`, which is why the entry above works. However, what if the exit - code needs to be different? A good example comes from the skip sample - job within the samples project: +In English, it says: "go to stepB if the exit code is `FAILED`". By default, the exit +code is always the same as the `BatchStatus` for the `Step`, which is why the entry above +works. However, what if the exit code needs to be different? A good example comes from +the skip sample job within the samples project: .XML Configuration [source, xml, role="xmlContent"] @@ -1881,25 +1557,15 @@ public Job job() { } ---- -The step1 has three possibilities: +`step1` has three possibilities: +. The `Step` failed, in which case the job should fail. +. The `Step` completed successfully. +. The `Step` completed successfully but with an exit code of 'COMPLETED WITH SKIPS'. In +this case, a different step should be run to handle the errors. -. The `Step` failed, in which case the - job should fail. - - -. The `Step` completed - successfully. - - -. The `Step` completed successfully but - with an exit code of 'COMPLETED WITH SKIPS'. In this case, a - different step should be run to handle the errors. - -The above configuration works. However, something needs to - change the exit code based on the condition of the execution having - skipped records, as shown in the following example: - +The above configuration works. However, something needs to change the exit code based on +the condition of the execution having skipped records, as shown in the following example: [source, java] ---- @@ -1917,31 +1583,22 @@ public class SkipCheckingListener extends StepExecutionListenerSupport { } ---- -The above code is a `StepExecutionListener` - that first checks to make sure the `Step` was - successful and then checks to see if the skip count on the - `StepExecution` is higher than 0. If both - conditions are met, a new `ExitStatus` with an - exit code of `COMPLETED WITH SKIPS` is returned. +The above code is a `StepExecutionListener` that first checks to make sure the `Step` was +successful and then checks to see if the skip count on the `StepExecution` is higher than +0. If both conditions are met, a new `ExitStatus` with an exit code of +`COMPLETED WITH SKIPS` is returned. [[configuringForStop]] - - ==== Configuring for Stop -After the discussion of <>, one might wonder how the - `BatchStatus` and `ExitStatus` - are determined for the `Job`. While these statuses - are determined for the `Step` by the code that is - executed, the statuses for the `Job` are - determined based on the configuration. - -So far, all of the job configurations discussed have had at least - one final `Step` with no transitions. For example, - after the following step executes, the `Job` - ends, as shown in the following example: +After the discussion of <>, +one might wonder how the `BatchStatus` and `ExitStatus` are determined for the `Job`. +While these statuses are determined for the `Step` by the code that is executed, the +statuses for the `Job` are determined based on the configuration. +So far, all of the job configurations discussed have had at least one final `Step` with +no transitions. For example, after the following step executes, the `Job` ends, as shown +in the following example: [source, xml, role="xmlContent"] ---- @@ -1958,71 +1615,47 @@ public Job job() { } ---- -If no transitions are defined for a `Step`, - then the `Job`'s statuses is defined as - follows: +If no transitions are defined for a `Step`, then the `Job`'s statuses is defined as +follows: +* If the `Step` ends with `ExitStatus` FAILED, then the `BatchStatus` and `ExitStatus` of +the `Job` are both `FAILED`. -* If the `Step` ends with - `ExitStatus` FAILED, then the - `BatchStatus` and - `ExitStatus` of the `Job` are both `FAILED`. +* Otherwise, the `BatchStatus` and `ExitStatus` of the `Job` are both `COMPLETED`. -* Otherwise, the - `BatchStatus` and - `ExitStatus` of the `Job` are both `COMPLETED`. - -While this method of terminating a batch job is sufficient for - some batch jobs, such as a simple sequential step job, custom defined - job-stopping scenarios may be required. For this purpose, Spring Batch - provides three transition elements to stop a `Job` - (in addition to the <> - that we discussed previously). Each of these stopping elements stops - a `Job` with a particular - `BatchStatus`. It is important to note that the - stop transition elements have no effect on either the - `BatchStatus` or `ExitStatus` - of any `Steps` in the `Job`. - These elements affect only the final statuses of the - `Job`. For example, it is possible for every step - in a job to have a status of `FAILED` but for the job to have a status of - `COMPLETED`. +While this method of terminating a batch job is sufficient for some batch jobs, such as a +simple sequential step job, custom defined job-stopping scenarios may be required. For +this purpose, Spring Batch provides three transition elements to stop a `Job` (in +addition to the <> that we discussed previously). +Each of these stopping elements stops a `Job` with a particular `BatchStatus`. It is +important to note that the stop transition elements have no effect on either the +`BatchStatus` or `ExitStatus` of any `Steps` in the `Job`. These elements affect only the +final statuses of the `Job`. For example, it is possible for every step in a job to have +a status of `FAILED` but for the job to have a status of `COMPLETED`. [[endElement]] - - ===== Ending at a Step -Configuring a step end instructs a `Job` to stop - with a `BatchStatus` of `COMPLETED`. A - `Job` that has finished with status `COMPLETED` - cannot be restarted (the framework throws a - `JobInstanceAlreadyCompleteException`). +Configuring a step end instructs a `Job` to stop with a `BatchStatus` of `COMPLETED`. A +`Job` that has finished with status `COMPLETED` cannot be restarted (the framework throws +a `JobInstanceAlreadyCompleteException`). [role="xmlContent"] -When using XML configuration, the 'end' element is used for this task. The `end` - element also allows for an optional 'exit-code' attribute that can be - used to customize the `ExitStatus` of the - `Job`. If no 'exit-code' attribute is given, then - the `ExitStatus` is `COMPLETED` by default, - to match the `BatchStatus`. +When using XML configuration, the 'end' element is used for this task. The `end` element +also allows for an optional 'exit-code' attribute that can be used to customize the +`ExitStatus` of the `Job`. If no 'exit-code' attribute is given, then the `ExitStatus` is +`COMPLETED` by default, to match the `BatchStatus`. [role="javaContent"] -When using Java configuration, the 'end' method is used for this task. The `end` - method also allows for an optional 'exitStatus' parameter that can be - used to customize the `ExitStatus` of the - `Job`. If no 'exitStatus' value is provided, then - the `ExitStatus` is `COMPLETED` by default, - to match the `BatchStatus`. - -In the following scenario, if `step2` fails, then the - `Job` stops with a - `BatchStatus` of `COMPLETED` and an - `ExitStatus` of `COMPLETED` and `step3` does not - run. Otherwise, execution moves to `step3`. Note that if `step2` - fails, the `Job` is not restartable (because - the status is `COMPLETED`). +When using Java configuration, the 'end' method is used for this task. The `end` method +also allows for an optional 'exitStatus' parameter that can be used to customize the +`ExitStatus` of the `Job`. If no 'exitStatus' value is provided, then the `ExitStatus` is +`COMPLETED` by default, to match the `BatchStatus`. +In the following scenario, if `step2` fails, then the `Job` stops with a `BatchStatus` of +`COMPLETED` and an `ExitStatus` of `COMPLETED` and `step3` does not run. Otherwise, +execution moves to `step3`. Note that if `step2` fails, the `Job` is not restartable +(because the status is `COMPLETED`). [source, xml, role="xmlContent"] ---- @@ -2051,30 +1684,22 @@ public Job job() { ---- [[failElement]] - - ===== Failing a Step -Configuring a step to fail at a given point instructs a `Job` to - stop with a `BatchStatus` of `FAILED`. Unlike end, the failing a `Job` does not - prevent the - `Job` from being restarted. +Configuring a step to fail at a given point instructs a `Job` to stop with a +`BatchStatus` of `FAILED`. Unlike end, the failing a `Job` does not prevent the `Job` +from being restarted. [role="xmlContent"] -When using XML configuration, the 'fail' element - also allows for an optional 'exit-code' attribute that can be used to - customize the `ExitStatus` of the - `Job`. If no 'exit-code' attribute is given, then - the `ExitStatus` is `FAILED` by default, to - match the `BatchStatus`. +When using XML configuration, the 'fail' element also allows for an optional 'exit-code' +attribute that can be used to customize the `ExitStatus` of the `Job`. If no 'exit-code' +attribute is given, then the `ExitStatus` is `FAILED` by default, to match the +`BatchStatus`. -In the following scenario, if `step2` fails, then the - `Job` will stop with a - `BatchStatus` of `FAILED` and an - `ExitStatus` of `EARLY TERMINATION` and `step3` - does not execute. Otherwise, execution moves to `step3`. - Additionally, if `step2` fails and the `Job` is - restarted, then execution begins again on `step2`. +In the following scenario, if `step2` fails, then the `Job` stops with a `BatchStatus` of +`FAILED` and an `ExitStatus` of `EARLY TERMINATION` and `step3` does not execute. +Otherwise, execution moves to `step3`. Additionally, if `step2` fails and the `Job` is +restarted, then execution begins again on `step2`. .XML Configuration [source, xml, role="xmlContent"] @@ -2104,30 +1729,22 @@ public Job job() { ---- [[stopElement]] - - ===== Stopping a Job at a Given Step -Configuring a job to stop at a particular step instructs a `Job` to - stop with a `BatchStatus` of `STOPPED`. Stopping a - `Job` can provide a temporary break in processing, - so that the operator can take some action before restarting the - `Job`. +Configuring a job to stop at a particular step instructs a `Job` to stop with a +`BatchStatus` of `STOPPED`. Stopping a `Job` can provide a temporary break in processing, +so that the operator can take some action before restarting the `Job`. [role="xmlContent"] -When using XML configuration 'stop' element requires a 'restart' - attribute that specifies the step where execution should pick up when - the "Job is restarted". +When using XML configuration 'stop' element requires a 'restart' attribute that specifies +the step where execution should pick up when the "Job is restarted". [role="javaContent"] -When using java configuration, the `stopAndRestar` method requires a 'restart' - attribute that specifies the step where execution should pick up when - the "Job is restarted". - -In the following scenario, if `step1` finishes with `COMPLETE`, then - the job will then stop. Once it is restarted, execution begins on - `step2`. +When using java configuration, the `stopAndRestart` method requires a 'restart' attribute +that specifies the step where execution should pick up when the "Job is restarted". +In the following scenario, if `step1` finishes with `COMPLETE`, then the job then stops. +Once it is restarted, execution begins on `step2`. [source, xml, role="xmlContent"] ---- @@ -2150,16 +1767,11 @@ public Job job() { ---- [[programmaticFlowDecisions]] - - ==== Programmatic Flow Decisions -In some situations, more information than the - `ExitStatus` may be required to decide which step - to execute next. In this case, a - `JobExecutionDecider` can be used to assist in the - decision, as shown in the following example: - +In some situations, more information than the `ExitStatus` may be required to decide +which step to execute next. In this case, a `JobExecutionDecider` can be used to assist +in the decision, as shown in the following example: [source, java] ---- @@ -2176,8 +1788,8 @@ public class MyDecider implements JobExecutionDecider { ---- [role="xmlContent"] -In the following sample job configuration, a `decision` specifies the - decider to use as well as all of the transitions: +In the following sample job configuration, a `decision` specifies the decider to use as +well as all of the transitions: .XML Configuration [source, xml, role="xmlContent"] @@ -2198,8 +1810,8 @@ In the following sample job configuration, a `decision` specifies the ---- [role="javaContent"] -In this example, a bean implementing the `JobExecutionDecider` is passed directly to the -`next` call when using Java configuration. +In the following example, a bean implementing the `JobExecutionDecider` is passed +directly to the `next` call when using Java configuration. .Java Configuration [source, java, role="javaContent"] @@ -2216,23 +1828,17 @@ public Job job() { ---- [[split-flows]] - - ==== Split Flows -Every scenario described so far has involved a - `Job` that executes its - `Steps` one at a time in a linear fashion. In - addition to this typical style, the Spring Batch also allows - for a job to be configured with parallel flows. +Every scenario described so far has involved a `Job` that executes its `Steps` one at a +time in a linear fashion. In addition to this typical style, the Spring Batch also allows +for a job to be configured with parallel flows. [role="xmlContent"] -The XML namespace allows you to use the 'split' - element. As the following example shows, the 'split' element contains one or more - 'flow' elements, where entire separate flows can be defined. A 'split' - element may also contain any of the previously discussed transition - elements, such as the 'next' attribute or the 'next', 'end', 'fail', or - 'pause' elements. +The XML namespace allows you to use the 'split' element. As the following example shows, +the 'split' element contains one or more 'flow' elements, where entire separate flows can +be defined. A 'split' element may also contain any of the previously discussed transition +elements, such as the 'next' attribute or the 'next', 'end', 'fail', or 'pause' elements. [source, xml, role="xmlContent"] ---- @@ -2249,12 +1855,11 @@ The XML namespace allows you to use the 'split' ---- [role="javaContent"] -Java based configuration allows you to configure splits via the provided builders. -As the following example shows, the 'split' element contains one or more - 'flow' elements, where entire separate flows can be defined. A 'split' - element may also contain any of the previously discussed transition - elements, such as the 'next' attribute or the 'next', 'end', 'fail', or - 'pause' elements. +Java based configuration lets you configure splits through the provided builders. As the +following example shows, the 'split' element contains one or more 'flow' elements, where +entire separate flows can be defined. A 'split' element may also contain any of the +previously discussed transition elements, such as the 'next' attribute or the 'next', +'end', 'fail', or 'pause' elements. [source, java, role="javaContent"] ---- @@ -2279,14 +1884,11 @@ public Job job() { ---- [[external-flows]] - - ==== Externalizing Flow Definitions and Dependencies Between Jobs -Part of the flow in a job can be externalized as a separate bean - definition and then re-used. There are two ways to do so. The - first is to simply declare the flow as a reference to one defined - elsewhere, as shown in the following example: +Part of the flow in a job can be externalized as a separate bean definition and then +re-used. There are two ways to do so. The first is to simply declare the flow as a +reference to one defined elsewhere, as shown in the following example: .XML Confguration [source, xml, role="xmlContent"] @@ -2323,17 +1925,15 @@ public Flow flow1() { } ---- -The effect of defining an external flow as shown in the preceding example is to - insert the steps from the external flow into the job as if they had been - declared inline. In this way, many jobs can refer to the same template - flow and compose such templates into different logical flows. This is - also a good way to separate the integration testing of the individual - flows. +The effect of defining an external flow as shown in the preceding example is to insert +the steps from the external flow into the job as if they had been declared inline. In +this way, many jobs can refer to the same template flow and compose such templates into +different logical flows. This is also a good way to separate the integration testing of +the individual flows. -The other form of an externalized flow is to use a - `JobStep`. A `JobStep` is - similar to a `FlowStep` but actually creates and - launches a separate job execution for the steps in the flow specified. +The other form of an externalized flow is to use a `JobStep`. A `JobStep` is similar to a +`FlowStep` but actually creates and launches a separate job execution for the steps in +the flow specified. [role="xmlContent"] The following XML snippet shows an example of a `JobStep`: @@ -2395,29 +1995,20 @@ public DefaultJobParametersExtractor jobParametersExtractor() { } ---- -The job parameters extractor is a strategy that determines how - the `ExecutionContext` for the - `Step` is converted into - `JobParameters` for the `Job` that is run. The - `JobStep` is useful when you want to have some more - granular options for monitoring and reporting on jobs and steps. Using - `JobStep` is also often a good answer to the - question: "How do I create dependencies between jobs?" It is a good way - to break up a large system into smaller modules and control the flow of - jobs. +The job parameters extractor is a strategy that determines how the `ExecutionContext` for +the `Step` is converted into `JobParameters` for the `Job` that is run. The `JobStep` is +useful when you want to have some more granular options for monitoring and reporting on +jobs and steps. Using `JobStep` is also often a good answer to the question: "How do I +create dependencies between jobs?" It is a good way to break up a large system into +smaller modules and control the flow of jobs. [[late-binding]] - - === Late Binding of `Job` and `Step` Attributes -Both the XML and flat file examples shown earlier use the Spring - `Resource` abstraction to obtain a file. This works - because `Resource` has a `getFile` - method, which returns a `java.io.File`. Both XML and - flat file resources can be configured using standard Spring - constructs, as shown in the following example: - +Both the XML and flat file examples shown earlier use the Spring `Resource` abstraction +to obtain a file. This works because `Resource` has a `getFile` method, which returns a +`java.io.File`. Both XML and flat file resources can be configured using standard Spring +constructs, as shown in the following example: .XML Configuration [source, xml, role="xmlContent"] @@ -2441,16 +2032,15 @@ public FlatFileItemReaer flatFileItemReader() { } ---- -The preceding `Resource` loads the file from - the specified file system location. Note that absolute locations have to - start with a double slash (`//`). In most Spring applications, this - solution is good enough, because the names of these resources are known at compile - time. However, in batch scenarios, the file name may need to be determined - at runtime as a parameter to the job. This can be solved using '-D' - parameters to read a system property. +The preceding `Resource` loads the file from the specified file system location. Note +that absolute locations have to start with a double slash (`//`). In most Spring +applications, this solution is good enough, because the names of these resources are +known at compile time. However, in batch scenarios, the file name may need to be +determined at runtime as a parameter to the job. This can be solved using '-D' parameters +to read a system property. [role="xmlContent"] -The following XML snippet shows how to read a file from a property: +The following XML snippet shows how to read a file name from a property: .XML Configuration [source, xml, role="xmlContent"] @@ -2462,7 +2052,7 @@ The following XML snippet shows how to read a file from a property: ---- [role="javaContent"] -The following Java snippet shows how to read a file from a property: +The following Java snippet shows how to read a file name from a property: .Java Configuration [source, java, role="javaContent"] @@ -2476,18 +2066,16 @@ public FlatFileItemReaer flatFileItemReader(@Value("${input.file.name}") String } ---- -All that would be required for this solution to work would be a - system argument (such as `-Dinput.file.name="file://file.txt"`). (Note that, although - a `PropertyPlaceholderConfigurer` can be used here, - it is not necessary if the system property is always set because the - `ResourceEditor` in Spring already filters and does - placeholder replacement on system properties.) +All that would be required for this solution to work would be a system argument (such as +`-Dinput.file.name="file://file.txt"`). (Note that, although a +`PropertyPlaceholderConfigurer` can be used here, it is not necessary if the system +property is always set because the `ResourceEditor` in Spring already filters and does +placeholder replacement on system properties.) -Often, in a batch setting, it is preferable to parameterize the file - name in the `JobParameters` of the - job, instead of through system properties, and access them that way. To - accomplish this, Spring Batch allows for the late binding of various `Job` - and `Step` attributes, as shown in the following snippet: +Often, in a batch setting, it is preferable to parameterize the file name in the +`JobParameters` of the job, instead of through system properties, and access them that +way. To accomplish this, Spring Batch allows for the late binding of various `Job` and +`Step` attributes, as shown in the following snippet: .XML Configuration [source, xml, role="xmlContent"] @@ -2511,10 +2099,8 @@ public FlatFileItemReader flatFileItemReader(@Value("#{jobParameters['input.file } ---- -Both the `JobExecution` and - `StepExecution` level - `ExecutionContext` can be accessed in the same - way, as shown in the following examples: +Both the `JobExecution` and `StepExecution` level `ExecutionContext` can be accessed in +the same way, as shown in the following examples: .XML Configuration [source, xml, role="xmlContent"] @@ -2560,39 +2146,17 @@ public FlatFileItemReader flatFileItemReader(@Value("#{stepExecutionContext['inp } ---- - [NOTE] ==== -Any bean that uses late-binding must be declared with - scope="step". See <> for more - information. +Any bean that uses late-binding must be declared with scope="step". See +<> for more information. ==== - - -[NOTE] -==== -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 that 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. -==== -// Where is that older language described? It'd be good to have a link to it here. -// Also, given that we're up to version 5 of Spring, should we still be talking about -// things from before version 3? (In other words, we should provide a link or drop the -// whole thing.) - [[step-scope]] - - ==== Step Scope -All of the late binding examples from above have a scope of "step" - declared on the bean definition, as shown in the following example: +All of the late binding examples from above have a scope of "step" declared on the bean +definition, as shown in the following example: .XML Configuration [source, xml, role="xmlContent"] @@ -2616,15 +2180,12 @@ public FlatFileItemReader flatFileItemReader(@Value("#{jobParameters[input.file. } ---- -Using a scope of `Step` is required in order - to use late binding, because the bean cannot actually be instantiated until - the `Step` starts, to allow the attributes to - be found. Because it is not part of the Spring container by default, the - scope must be added explicitly, by using the - `batch` namespace or by including a bean definition explicitly for the - StepScope, or by using the `@EnableBatchProcessing` annotation. Use only one of - those methods. The following example uses the `batch` namespace: - +Using a scope of `Step` is required in order to use late binding, because the bean cannot +actually be instantiated until the `Step` starts, to allow the attributes to be found. +Because it is not part of the Spring container by default, the scope must be added +explicitly, by using the `batch` namespace or by including a bean definition explicitly +for the `StepScope`, or by using the `@EnableBatchProcessing` annotation. Use only one of +those methods. The following example uses the `batch` namespace: [source, xml] ---- @@ -2639,24 +2200,20 @@ Using a scope of `Step` is required in order The following example includes the bean definition explicitly: - [source, xml] ---- ---- [[job-scope]] - - ==== Job Scope -`Job` scope, introduced in Spring Batch 3.0, is similar to `Step` scope - in configuration but is a Scope for the `Job` context, so that there is only one - instance of such a bean per running job. Additionally, support is provided - for late binding of references accessible from the `JobContext` using - `#{..}` placeholders. Using this feature, bean properties can be pulled from - the job or job execution context and the job parameters, as shown in the following examples: - +`Job` scope, introduced in Spring Batch 3.0, is similar to `Step` scope in configuration +but is a Scope for the `Job` context, so that there is only one instance of such a bean +per running job. Additionally, support is provided for late binding of references +accessible from the `JobContext` using `#{..}` placeholders. Using this feature, bean +properties can be pulled from the job or job execution context and the job parameters, as +shown in the following examples: .XML Configurtation [source, xml, role="xmlContent"] @@ -2700,12 +2257,10 @@ public FlatFileItemReader flatFileItemReader(@Value("#{jobExecutionContext['inpu } ---- -Because it is not part of the Spring container by default, the scope - must be added explicitly, by using the `batch` namespace, by including a - bean definition explicitly for the JobScope, or using the `@EnableBatchProcessing` - annotation (but not all of them). The following example - uses the `batch` namespace: - +Because it is not part of the Spring container by default, the scope must be added +explicitly, by using the `batch` namespace, by including a bean definition explicitly for +the JobScope, or using the `@EnableBatchProcessing` annotation (but not all of them). +The following example uses the `batch` namespace: [source, xml] ----