Controlling Step Flow

有了将步骤组合在一起,并将它们与拥有作业的能力,就需要能够控制作业如何从一个步骤“流向”另一个步骤。Step 的故障并不一定意味着 Job 应该失败。此外,可能有多种类型的“success”决定应该执行哪一个 Step。取决于 Steps 组的配置方式,某些步骤甚至可能根本不会被处理。

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. .Step bean method proxying in flow definitions

一个步骤实例在流程定义中必须是唯一的。当一个步骤在流程定义中具有多个结果时,重要的是将步骤的相同实例传递给流程定义方法(startfrom 等)。否则,流程执行可能会表现得非常意外。

A step instance must be unique within a flow definition. When a step has multiple outcomes in a flow definition, it is important that the same instance of the step is passed to the flow definition methods (start, from, etc). Otherwise, the flow execution might behave unexpectedly.

在以下示例中,步骤被注入为流程或作业 bean 定义方法的参数。这种依赖项注入保证了流程定义中步骤的唯一性。但是,如果流程是通过调用带 @Bean 注释的步骤定义方法来定义的,那么如果禁用了 bean 方法代理(即 @Configuration(proxyBeanMethods = false)),则步骤可能不是唯一的。如果首选 bean 间注入风格,则必须启用 bean 方法代理。

In the following examples, steps are injected as parameters to the flow or job bean definition methods. This dependency injection style guarantees the uniqueness of steps in the flow definition. However, if the flow is defined by calling step definition methods annotated with @Bean, then steps might not be unique if bean method proxying is disabled (ie @Configuration(proxyBeanMethods = false)). If the inter-bean injection style is preferred, then bean method proxying must be enabled.

请参阅 Using the @Configuration annotation部分以获取有关在 Spring 框架中进行 Bean 方法代理的更多详细信息。

Please refer to the Using the @Configuration annotation section for more details about bean method proxying in Spring Framework.

Sequential Flow

最简单的流程场景是其中所有步骤顺序执行的作业,如下所示:

The simplest flow scenario is a job where all of the steps execute sequentially, as the following image shows:

sequential flow
Figure 1. Sequential Flow

这可以通过在 step 中使用 next 来实现。

This can be achieved by using next in a step.

Java

以下示例展示了如何在 Java 中使用 next() 方法:

The following example shows how to use the next() method in Java:

Java Configuration
@Bean
public Job job(JobRepository jobRepository, Step stepA, Step stepB, Step stepC) {
	return new JobBuilder("job", jobRepository)
				.start(stepA)
				.next(stepB)
				.next(stepC)
				.build();
}
XML

以下示例展示了如何在 XML 中使用 next 属性:

The following example shows how to use the next attribute in XML:

XML Configuration
<job id="job">
    <step id="stepA" parent="s1" next="stepB" />
    <step id="stepB" parent="s2" next="stepC"/>
    <step id="stepC" parent="s3" />
</job>

在上面的场景中,stepA 先运行,因为它是最先列出的 Step。如果 stepA 正常完成,则 stepB 运行,依此类推。但是,如果 step A 失败,则整个 Job 失败,且 stepB 不会执行。

In the scenario above, stepA runs first because it is the first Step listed. If stepA completes normally, stepB runs, and so on. However, if step A fails, the entire Job fails and stepB does not execute.

在 Spring Batch XML 命名空间中,在配置中列出的第一个步骤是_always_ 由 Job 运行的第一个步骤。其他步骤元素的顺序无关紧要,但第一个步骤必须始终在 XML 中首先出现。

With the Spring Batch XML namespace, the first step listed in the configuration is always the first step run by the Job. The order of the other step elements does not matter, but the first step must always appear first in the XML.

Conditional Flow

在前一个示例中,只存在两种可能性:

In the preceding example, there are only two possibilities:

  1. The step is successful, and the next step should be executed.

  2. The step failed, and, thus, the job should fail.

在许多情况下,这可能就足够了。然而,对于一个场景又如何呢?在这种场景中,step 的故障应触发另一个 step,而不是导致故障?下图展示了这样的一个流程:

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
Figure 2. Conditional Flow
Java

Java API 提供了一组流畅的方法,让你能够指定流程以及在步骤失败时要做什么。以下示例展示了如何指定一个步骤 (stepA),然后根据 stepA 是否成功进入两个不同的步骤 (stepBstepC) 中的任意一个:

The Java API offers a fluent set of methods that let you specify the flow and what to do when a step fails. The following example shows how to specify one step (stepA) and then proceed to either of two different steps (stepB or stepC), depending on whether stepA succeeds:

Java Configuration
@Bean
public Job job(JobRepository jobRepository, Step stepA, Step stepB, Step stepC) {
	return new JobBuilder("job", jobRepository)
				.start(stepA)
				.on("*").to(stepB)
				.from(stepA).on("FAILED").to(stepC)
				.end()
				.build();
}
XML

为了处理更复杂的场景,Spring Batch XML 命名空间让你能够在步骤元素中定义过渡元素。其中一个这样的过渡是 next 元素。像 next 属性一样,next 元素会告诉 Job 接下来的要执行哪个 Step。但是,与属性不同,允许在给定的 Step 上使用任意数量的 next 元素,並且在故障的情况下没有默认行为。这意味着,如果使用了过渡元素,则必须显式定义 Step 过渡的所有行为。另请注意,单个步骤不能同时具有 next 属性和 transition 元素。

To handle more complex scenarios, the Spring Batch XML namespace lets you define transitions elements 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 in the case of failure. This means that, if transition elements are used, 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.

next 元素指定了一个要匹配的模式以及要接下来执行的步骤,如下例所示:

The next element specifies a pattern to match and the step to execute next, as the following example shows:

XML Configuration
<job id="job">
    <step id="stepA" parent="s1">
        <next on="*" to="stepB" />
        <next on="FAILED" to="stepC" />
    </step>
    <step id="stepB" parent="s2" next="stepC" />
    <step id="stepC" parent="s3" />
</job>
Java

当使用 Java 配置时,on() 方法使用一个简单的模式匹配方案来匹配 Step 执行过程中产生的 ExitStatus

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.

XML

当使用 XML 配置时,过渡元素的 on 属性使用一个简单的模式匹配方案来匹配 Step 执行过程中产生的 ExitStatus

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.

模式中只允许两个特殊字符:

Only two special characters are allowed in the pattern:

  • * matches zero or more characters

  • ? matches exactly one character

例如,c*t 匹配 catcount,而 c?t 匹配 cat 但不匹配 count

For example, c*t matches cat and count, while c?t matches cat but not count.

虽然 Step 上的转换元素数量没有限制,但是,如果 Step 执行导致的 ExitStatus 并未被元素涵盖,那么框架将抛出异常,并且 Job 将失败。该框架会自动对转换按从最具体到最不具体进行排序。这意味着,即使在前面的示例中 stepA 的排序被交换,FAILEDExitStatus 仍然会进入 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, 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 preceding example, an ExitStatus of FAILED would still go to stepC.

Batch Status Versus Exit Status

Job 配置条件流程时,了解 BatchStatusExitStatus 之间的区别非常重要。BatchStatus 是一个枚举,既是 JobExecution 也是 StepExecution 的属性,并且由框架用于记录 JobStep 的状态。它可以是以下值之一:COMPLETEDSTARTINGSTARTEDSTOPPINGSTOPPEDFAILEDABANDONEDUNKNOWN。其中多数是不言自明的:COMPLETED 是步骤或作业成功完成后设置的状态,FAILED 是失败后设置的状态,依此类推。

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.

Java

在使用 Java 配置时,以下示例包含 on 元素:

The following example contains the on element when using Java Configuration:

...
.from(stepA).on("FAILED").to(stepB)
...
XML

在使用 XML 配置时,以下示例包含 next 元素:

The following example contains the next element when using XML configuration:

<next on="FAILED" to="stepB" />

乍一看,on 似乎引用了它所属 StepBatchStatus。但是,它实际上引用了 StepExitStatus。顾名思义,ExitStatus 表示 Step 在完成执行后的状态。

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.

Java

在使用 Java 配置时,在前面的 Java 配置示例中显示的 on() 方法引用了 ExitStatus 的退出代码。

When using Java configuration, the on() method shown in the preceding Java configuration example references the exit code of ExitStatus.

XML

更具体地说,在使用 XML 配置时,在前面的 XML 配置示例中显示的 next 元素引用了 ExitStatus 的退出代码。

More specifically, when using XML configuration, the next element shown in the preceding XML configuration example references the exit code of ExitStatus.

用英语说就是:“如果退出代码为 FAILED,则转到 stepB”。默认情况下,退出代码始终与 StepBatchStatus 相同,这就是前面的条目有效的原因。但是,如果需要让退出代码不同怎么办?一个很好的例子是样本项目中的跳过样本作业:

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 preceding entry works. However, what if the exit code needs to be different? A good example comes from the skip sample job within the samples project:

Java

以下示例显示了如何在 Java 中使用不同的退出代码:

The following example shows how to work with a different exit code in Java:

Java Configuration
@Bean
public Job job(JobRepository jobRepository, Step step1, Step step2, Step errorPrint1) {
	return new JobBuilder("job", jobRepository)
			.start(step1).on("FAILED").end()
			.from(step1).on("COMPLETED WITH SKIPS").to(errorPrint1)
			.from(step1).on("*").to(step2)
			.end()
			.build();
}
XML

以下示例显示了如何在 XML 中使用不同的退出代码:

The following example shows how to work with a different exit code in XML:

XML Configuration
<step id="step1" parent="s1">
    <end on="FAILED" />
    <next on="COMPLETED WITH SKIPS" to="errorPrint1" />
    <next on="*" to="step2" />
</step>

step1 有三种可能:

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 preceding configuration works. However, something needs to change the exit code based on the condition of the execution having skipped records, as the following example shows:

public class SkipCheckingListener extends StepExecutionListenerSupport {
    public ExitStatus afterStep(StepExecution stepExecution) {
        String exitCode = stepExecution.getExitStatus().getExitCode();
        if (!exitCode.equals(ExitStatus.FAILED.getExitCode()) &&
              stepExecution.getSkipCount() > 0) {
            return new ExitStatus("COMPLETED WITH SKIPS");
        }
        else {
            return null;
        }
    }
}

前面的代码是 StepExecutionListener,首先检查以确保 Step 成功,然后检查 StepExecution 中的跳过计数是否高于 0。如果满足这两个条件,则会返回一个新的具有退出代码 COMPLETED WITH SKIPSExitStatus

The preceding 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.

Configuring for Stop

在对 BatchStatus and ExitStatus进行讨论后,人们可能会好奇 `BatchStatus`和 `ExitStatus`如何针对 `Job`进行确定。虽然这些状态由执行的代码为 `Step`确定,但 `Job`的状态根据配置确定。

After the discussion of BatchStatus and ExitStatus, 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.

到目前为止,所讨论的所有作业配置都至少有一个无转换的最终 Step

So far, all of the job configurations discussed have had at least one final Step with no transitions.

Java

在以下 Java 示例中,在 step 执行后,Job 结束:

In the following Java example, after the step executes, the Job ends:

@Bean
public Job job(JobRepository jobRepository, Step step1) {
	return new JobBuilder("job", jobRepository)
				.start(step1)
				.build();
}
XML

在以下 XML 示例中,在 step 执行后,Job 结束:

In the following XML example, after the step executes, the Job ends:

<step id="step1" parent="s3"/>

如果未为 Step 定义转换,则 Job 的状态将按如下方式定义:

If no transitions are defined for a Step, the status of the Job is defined as follows:

  • If the Step ends with ExitStatus of FAILED, the BatchStatus and ExitStatus of the Job are both FAILED.

  • Otherwise, the BatchStatus and ExitStatus of the Job are both COMPLETED.

虽然这种终止批处理作业的方法对于某些批处理作业(例如简单的顺序步骤作业)来说已经足够,但可能需要自定义定义的作业停止情形。为此,Spring Batch 提供三个转换元素来停止 Job(除了我们之前讨论的 xref:step/controlling-flow.adoc#nextElement[next 元素)。这些停止元素中的每一个都以特定 BatchStatus 停止 Job。需要注意的是,停止转换元素对 Job 中任何 StepsBatchStatusExitStatus 都没有影响。这些元素仅影响 Job 的最终状态。例如,作业中的每个步骤的状态都可能是 FAILED,但作业的状态为 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 next element 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.

Ending at a Step

配置步骤结束会指导“作业”停止,其“批处理状态”为“完成”。已结束且状态为“完成”的“作业”无法重新启动(该框架会引发`JobInstanceAlreadyCompleteException`)。

Configuring a step end instructs a Job to stop with a BatchStatus of COMPLETED. A Job that has finished with a status of COMPLETED cannot be restarted (the framework throws a JobInstanceAlreadyCompleteException).

Java

使用 Java 配置时,end 方法用于该任务。end 方法还允许有一个可选的`exitStatus`参数,你可以用它来自定义“作业”的`ExitStatus`。如果未提供`exitStatus`值,那么为了与“批处理状态”匹配,ExitStatus`默认值为`COMPLETED(完成)

When using Java configuration, the end method is used for this task. The end method also allows for an optional exitStatus parameter that you can use to customize the ExitStatus of the Job. If no exitStatus value is provided, the ExitStatus is COMPLETED by default, to match the BatchStatus.

XML

使用 XML 配置时,你可以使用`end`元素来执行该任务。end`元素还允许有一个可选的`exit-code`属性,你可以用它来自定义“作业”的`ExitStatus。如果未提供`exit-code`属性,那么为了与“批处理状态”匹配,ExitStatus`默认值为`COMPLETED(已完成)

When using XML configuration, you can use the end element for this task. The end element also allows for an optional exit-code attribute that you can use to customize the ExitStatus of the Job. If no exit-code attribute is given, the ExitStatus is COMPLETED by default, to match the BatchStatus.

考虑以下场景:如果`step2`失败,那么“作业”会停止,“批处理状态”为`COMPLETED(已完成),`ExitStatus`为`COMPLETED(已完成),而且`step3`不会运行。否则,执行会转到`step3`。注意,如果`step2`失败,那么“作业”不可重新启动(因为状态为`COMPLETED(完成)`)。

Consider the following scenario: If step2 fails, 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).

Java

以下示例用 Java 展示了该场景:

The following example shows the scenario in Java:

@Bean
public Job job(JobRepository jobRepository, Step step1, Step step2, Step step3) {
	return new JobBuilder("job", jobRepository)
				.start(step1)
				.next(step2)
				.on("FAILED").end()
				.from(step2).on("*").to(step3)
				.end()
				.build();
}
XML

以下示例用 XML 展示了该场景:

The following example shows the scenario in XML:

<step id="step1" parent="s1" next="step2">

<step id="step2" parent="s2">
    <end on="FAILED"/>
    <next on="*" to="step3"/>
</step>

<step id="step3" parent="s3">

Failing a Step

配置步骤在某个点失败会指导“作业”停止,其“批处理状态”为`FAILED(失败)`。与`end`不同,“作业”发生故障并不会阻止“作业”重新启动。

Configuring a step to fail at a given point instructs a Job to stop with a BatchStatus of FAILED. Unlike end, the failure of a Job does not prevent the Job from being restarted.

使用 XML 配置时,fail`元素还允许有一个可选的`exit-code`属性,该属性可用于自定义“作业”的`ExitStatus。如果未提供`exit-code`属性,那么为了与“批处理状态”匹配,ExitStatus`默认值为`FAILED(失败)

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, the ExitStatus is FAILED by default, to match the BatchStatus.

考虑以下场景:如果`step2`失败,那么“作业”会停止,“批处理状态”为`FAILED(失败),`ExitStatus`为`EARLY TERMINATION(早期终止),而且`step3`不会执行。否则,执行会转到`step3`。此外,如果`step2`失败,而且“作业”重新启动,那么会在`step2`重新开始执行。

Consider the following scenario: If step2 fails, 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, execution begins again on step2.

Java

以下示例用 Java 展示了该场景:

The following example shows the scenario in Java:

Java Configuration
@Bean
public Job job(JobRepository jobRepository, Step step1, Step step2, Step step3) {
	return new JobBuilder("job", jobRepository)
			.start(step1)
			.next(step2).on("FAILED").fail()
			.from(step2).on("*").to(step3)
			.end()
			.build();
}
XML

以下示例用 XML 展示了该场景:

The following example shows the scenario in XML:

XML Configuration
<step id="step1" parent="s1" next="step2">

<step id="step2" parent="s2">
    <fail on="FAILED" exit-code="EARLY TERMINATION"/>
    <next on="*" to="step3"/>
</step>

<step id="step3" parent="s3">

Stopping a Job at a Given Step

配置“作业”在特定步骤停止会指导“作业”停止,其“批处理状态”为`STOPPED(已停止)`。停止“作业”可以在处理过程中提供一个临时中断,以便操作者在重新启动“作业”前采取一些措施。

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.

Java

使用 Java 配置时,`stopAndRestart`方法需要一个`restart`属性,该属性指定“作业”重新启动后应该从哪个步骤开始执行。

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.

XML

使用 XML 配置时,`stop`元素需要一个`restart`属性,该属性指定“作业”重新启动后应该从哪个步骤开始执行。

When using XML configuration, a stop element requires a restart attribute that specifies the step where execution should pick up when the Job is restarted.

考虑以下场景:如果`step1`完成的状态为`COMPLETE(已完成)`,那么“作业”随后会停止。在重新启动后,会从`step2`开始执行。

Consider the following scenario: If step1 finishes with COMPLETE, the job then stops. Once it is restarted, execution begins on step2.

Java

以下示例用 Java 展示了该场景:

The following example shows the scenario in Java:

@Bean
public Job job(JobRepository jobRepository, Step step1, Step step2) {
	return new JobBuilder("job", jobRepository)
			.start(step1).on("COMPLETED").stopAndRestart(step2)
			.end()
			.build();
}
XML

以下清单用 XML 展示了该场景:

The following listing shows the scenario in XML:

<step id="step1" parent="s1">
    <stop on="COMPLETED" restart="step2"/>
</step>

<step id="step2" parent="s2"/>

Programmatic Flow Decisions

在某些情况下,可能需要比`ExitStatus`更多信息才能决定接下来要执行哪个步骤。在这种情况下,可以使用`JobExecutionDecider`来协助决策,如下例所示:

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 the following example shows:

public class MyDecider implements JobExecutionDecider {
    public FlowExecutionStatus decide(JobExecution jobExecution, StepExecution stepExecution) {
        String status;
        if (someCondition()) {
            status = "FAILED";
        }
        else {
            status = "COMPLETED";
        }
        return new FlowExecutionStatus(status);
    }
}
Java

在以下示例中,使用 Java 配置时,实现了`JobExecutionDecider`的 Bean 会直接传递到`next`调用中:

In the following example, a bean implementing the JobExecutionDecider is passed directly to the next call when using Java configuration:

Java Configuration
@Bean
public Job job(JobRepository jobRepository, MyDecider decider, Step step1, Step step2, Step step3) {
	return new JobBuilder("job", jobRepository)
			.start(step1)
			.next(decider).on("FAILED").to(step2)
			.from(decider).on("COMPLETED").to(step3)
			.end()
			.build();
}
XML

在以下作业配置示例中,`decision`指定要使用的决策模块以及所有转换:

In the following sample job configuration, a decision specifies the decider to use as well as all of the transitions:

XML Configuration
<job id="job">
    <step id="step1" parent="s1" next="decision" />

    <decision id="decision" decider="decider">
        <next on="FAILED" to="step2" />
        <next on="COMPLETED" to="step3" />
    </decision>

    <step id="step2" parent="s2" next="step3"/>
    <step id="step3" parent="s3" />
</job>

<beans:bean id="decider" class="com.MyDecider"/>

Split Flows

到目前为止描述的每一种情况都涉及一个“作业”,该“作业”以线性方式一次执行一个步骤。除了这种典型风格外,Spring Batch 还允许使用并行流来配置“作业”。

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, Spring Batch also allows for a job to be configured with parallel flows.

Java

基于 Java 的配置允许你通过提供的构建器配置拆分。如下例所示,split`元素包含一个或多个`flow`元素,可以在其中定义完全独立的流。`split`元素还可以包含前面讨论过的任何转换元素,如`next`属性或`next、`end`或`fail`元素。

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 can also contain any of the previously discussed transition elements, such as the next attribute or the next, end, or fail elements.

@Bean
public Flow flow1(Step step1, Step step2) {
	return new FlowBuilder<SimpleFlow>("flow1")
			.start(step1)
			.next(step2)
			.build();
}

@Bean
public Flow flow2(Step step3) {
	return new FlowBuilder<SimpleFlow>("flow2")
			.start(step3)
			.build();
}

@Bean
public Job job(JobRepository jobRepository, Flow flow1, Flow flow2, Step step4) {
	return new JobBuilder("job", jobRepository)
				.start(flow1)
				.split(new SimpleAsyncTaskExecutor())
				.add(flow2)
				.next(step4)
				.end()
				.build();
}
XML

XML 命名空间允许你使用`split`元素。如下例所示,split`元素包含一个或多个`flow`元素,可以在其中定义完全独立的流。`split`元素还可以包含前面讨论过的任何转换元素,如`next`属性或`next、`end`或`fail`元素。

The XML namespace lets you 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 can also contain any of the previously discussed transition elements, such as the next attribute or the next, end, or fail elements.

<split id="split1" next="step4">
    <flow>
        <step id="step1" parent="s1" next="step2"/>
        <step id="step2" parent="s2"/>
    </flow>
    <flow>
        <step id="step3" parent="s3"/>
    </flow>
</split>
<step id="step4" parent="s4"/>

Externalizing Flow Definitions and Dependencies Between Jobs

作业中的部分流程可以被声明为一个单独的 bean 定义,然后被重用。有两种方法可以做到这一点。首先是声明流程为对其他地方定义的流程引用。

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 declare the flow as a reference to one defined elsewhere.

Java

以下 Java 示例显示如何声明流程为对其他地方定义的流程的引用:

The following Java example shows how to declare a flow as a reference to a flow defined elsewhere:

Java Configuration
@Bean
public Job job(JobRepository jobRepository, Flow flow1, Step step3) {
	return new JobBuilder("job", jobRepository)
				.start(flow1)
				.next(step3)
				.end()
				.build();
}

@Bean
public Flow flow1(Step step1, Step step2) {
	return new FlowBuilder<SimpleFlow>("flow1")
			.start(step1)
			.next(step2)
			.build();
}
XML

以下 XML 示例显示如何声明流程为对其他地方定义的流程的引用:

The following XML example shows how to declare a flow as a reference to a flow defined elsewhere:

XML Configuration
<job id="job">
    <flow id="job1.flow1" parent="flow1" next="step3"/>
    <step id="step3" parent="s3"/>
</job>

<flow id="flow1">
    <step id="step1" parent="s1" next="step2"/>
    <step id="step2" parent="s2"/>
</flow>

如前例所示,定义一个外部流程的效果是将外部流程中的步骤插入作业中,就好像它们已内联声明一样。通过这种方式,很多作业都可以引用相同的模板流程,并将这样的模板组合成不同的逻辑流程。这还是分离单个流程的集成测试的一种好方法。

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.

外部流程的另一种形式是使用 JobStepJobStep 类似于 FlowStep,但实际上会创建并启动一个单独的作业执行,用于在指定流程中的步骤。

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.

Java

以下示例显示了 Java 中 JobStep 的示例:

The following example shows an example of a JobStep in Java:

Java Configuration
@Bean
public Job jobStepJob(JobRepository jobRepository, Step jobStepJobStep1) {
	return new JobBuilder("jobStepJob", jobRepository)
				.start(jobStepJobStep1)
				.build();
}

@Bean
public Step jobStepJobStep1(JobRepository jobRepository, JobLauncher jobLauncher, Job job, JobParametersExtractor jobParametersExtractor) {
	return new StepBuilder("jobStepJobStep1", jobRepository)
				.job(job)
				.launcher(jobLauncher)
				.parametersExtractor(jobParametersExtractor)
				.build();
}

@Bean
public Job job(JobRepository jobRepository) {
	return new JobBuilder("job", jobRepository)
				// ...
				.build();
}

@Bean
public DefaultJobParametersExtractor jobParametersExtractor() {
	DefaultJobParametersExtractor extractor = new DefaultJobParametersExtractor();

	extractor.setKeys(new String[]{"input.file"});

	return extractor;
}
XML

以下示例显示了 XML 中 JobStep 的示例:

The following example hows an example of a JobStep in XML:

XML Configuration
<job id="jobStepJob" restartable="true">
   <step id="jobStepJob.step1">
      <job ref="job" job-launcher="jobLauncher"
          job-parameters-extractor="jobParametersExtractor"/>
   </step>
</job>

<job id="job" restartable="true">...</job>

<bean id="jobParametersExtractor" class="org.spr...DefaultJobParametersExtractor">
   <property name="keys" value="input.file"/>
</bean>

作业参数提取器是一种策略,它确定如何将 StepExecutionContext 转换为运行中的 JobJobParameters。当您想要对作业和步骤进行更精细的选项监控和报告时,JobStep 会很有用。使用 JobStep 通常也是回答“如何在作业之间创建依赖关系?”这一问题的不错答案。它是一种将大型系统分解为更小的模块并控制作业流的好方法。

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.