控制 Step Flow
随着能够在拥有作业中将步骤组合在一起,需要能够
来控制作业如何从一个步骤“流”到另一个步骤。a 的失败不会
必然意味着 应该失败。此外,可能有多种类型
的 “success” 中,确定接下来应该执行哪个。根据
组,则某些步骤甚至可能根本不被处理。Step
Job
Step
Steps
流程定义中的 Step Bean 方法代理
步骤实例在流程定义中必须是唯一的。当一个步骤在流程定义中具有多个结果时,
将步骤的相同实例传递给流定义方法(、 、 等)非常重要。
否则,流程执行可能会发生意外行为。 在以下示例中,步骤作为参数注入到流或作业 Bean 定义方法中。这种依赖关系注入样式保证了流程定义中步骤的唯一性。
但是,如果流是通过调用注释有 的步骤定义方法定义的,则如果禁用了 bean 方法代理(即 ),则步骤可能不唯一。
如果首选 bean 间注入样式,则必须启用 bean 方法代理。 请参阅 使用 @Configuration 注释 部分,以了解有关 Spring Framework 中 bean 方法代理的更多详细信息。 |
顺序流
最简单的流场景是所有步骤按顺序执行的作业,因为 下图显示了:
这可以通过在 .next
step
-
Java
-
XML
以下示例演示如何在 Java 中使用该方法:next()
@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 中使用该属性:next
<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
对于 Spring Batch XML 命名空间,配置中列出的第一步始终是由 .其他步骤元素的顺序不会
很重要,但第一步必须始终首先出现在 XML 中。Job |
条件流
在前面的示例中,只有两种可能性:
-
操作成功,下一步应执行。
step
step
-
失败的,因此,应该失败。
step
job
在许多情况下,这可能就足够了。但是,如果
失败的 a 应该触发不同的 ,而不是导致失败?这
下图显示了这样的流程:step
step
-
Java
-
XML
Java API 提供了一组 Fluent 方法,允许您指定流和要执行的操作
当步骤失败时。以下示例显示如何指定一个步骤 (),然后
继续执行两个不同步骤( 或 )中的任意一个,具体取决于是否成功:stepA
stepB
stepC
stepA
@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();
}
为了处理更复杂的情况,Spring Batch XML 命名空间允许您定义转换
元素。其中一种过渡是 element。与属性一样,元素告诉 which to
执行 next。但是,与 attribute 不同的是,允许在
给定的 ,并且在失败的情况下没有默认行为。这意味着,如果
transition 元素,则 transition 的所有行为都必须是
显式定义。另请注意,单个步骤不能同时具有属性和
一个元素。next
next
next
Job
Step
next
Step
Step
next
transition
该元素指定要匹配的模式和接下来要执行的步骤,如
以下示例显示:next
<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
-
XML
当使用 java 配置时,该方法使用简单的模式匹配方案来
匹配执行 .on()
ExitStatus
Step
使用 XML 配置时,transition 元素的属性使用简单的
pattern-matching 方案匹配 ,以匹配执行 .on
ExitStatus
Step
模式中只允许使用两个特殊字符:
-
*
匹配零个或多个字符 -
?
只匹配一个字符
例如,matches 和 ,while matches but not .c*t
cat
count
c?t
cat
count
虽然 上的过渡元素数量没有限制 ,但如果执行导致 an 未被元素覆盖,则
framework 引发异常,并且失败。框架会自动排序
从最特异性到最不特异性的转换。这意味着,即使
在前面的示例中交换,则 OF 仍会
自。Step
Step
ExitStatus
Job
stepA
ExitStatus
FAILED
stepC
批处理状态与退出状态
配置 for 条件流时,了解
和 之间的区别。 是一个枚举,其中
是 和 和 的属性,框架使用它来
记录 或 的状态。它可以是以下值之一: 、 、 、 、 或 。它们中的大多数是不言自明的:是当一个步骤
或 Job 已成功完成,在失败时设置,依此类推。Job
BatchStatus
ExitStatus
BatchStatus
JobExecution
StepExecution
Job
Step
COMPLETED
STARTING
STARTED
STOPPING
STOPPED
FAILED
ABANDONED
UNKNOWN
COMPLETED
FAILED
-
Java
-
XML
以下示例包含使用 Java 配置时的元素:on
...
.from(stepA).on("FAILED").to(stepB)
...
以下示例包含使用 XML 配置时的元素:next
<next on="FAILED" to="stepB" />
乍一看,似乎引用了 to
它属于它。但是,它实际上引用了 .由于
name 表示 A 完成执行后的状态。on
BatchStatus
Step
ExitStatus
Step
ExitStatus
Step
-
Java
-
XML
使用 Java 配置时,前面显示的方法
Java 配置示例引用了 的退出代码。on()
ExitStatus
更具体地说,在使用 XML 配置时,
前面的 XML 配置示例引用了 的退出代码。next
ExitStatus
在英语中,它说:“如果退出代码为 FAILED,则转到 stepB”。默认情况下,exit
code 始终与 for the 相同,这就是为什么前面的条目
工程。但是,如果退出代码需要不同,该怎么办?一个很好的例子来自
Samples 项目中的 Skip Sample 作业:BatchStatus
Step
-
Java
-
XML
以下示例演示如何在 Java 中使用不同的退出代码:
@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 中使用不同的退出代码:
<step id="step1" parent="s1">
<end on="FAILED" />
<next on="COMPLETED WITH SKIPS" to="errorPrint1" />
<next on="*" to="step2" />
</step>
step1
有三种可能性:
-
失败,在这种情况下,作业应失败。
Step
-
成功完成。
Step
-
成功完成,但退出代码为 。在 在这种情况下,应运行不同的步骤来处理错误。
Step
COMPLETED WITH SKIPS
上述配置有效。但是,需要根据 执行跳过记录的条件,如下例所示:
public class SkipCheckingListener implements StepExecutionListener {
@Override
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;
}
}
}
前面的代码是首先检查以确保
成功,然后检查 的跳过计数是否高于
0. 如果两个条件都满足,则返回退出代码为 new 的 new。StepExecutionListener
Step
StepExecution
ExitStatus
COMPLETED WITH SKIPS
配置 Stop
在讨论了 BatchStatus
和 ExitStatus
之后,
人们可能想知道 和 是如何确定 的。
虽然这些状态是由执行的代码确定的,但
的状态是根据配置确定的。BatchStatus
ExitStatus
Job
Step
Job
到目前为止,讨论的所有作业配置都至少有一个 final with
无过渡。Step
-
Java
-
XML
在下面的 Java 示例中,执行后, end:step
Job
@Bean
public Job job(JobRepository jobRepository, Step step1) {
return new JobBuilder("job", jobRepository)
.start(step1)
.build();
}
在下面的 XML 示例中,执行后, end:step
Job
<step id="step1" parent="s3"/>
如果未为 定义过渡 ,则 的状态定义为
遵循:Step
Job
-
如果以 of 结尾,则 和 这两者都是 .
Step
ExitStatus
FAILED
BatchStatus
ExitStatus
Job
FAILED
-
否则,的 和 都是 。
BatchStatus
ExitStatus
Job
COMPLETED
虽然这种终止批处理作业的方法对于某些批处理作业(如
可能需要简单的 Sequential Step Job,自定义 Job-Stopping 场景。为
为此,Spring Batch 提供了三个 transition 元素来停止一个 (在
添加到我们之前讨论的下一个
元素中)。
这些 stop 元素中的每一个都使用特定的 .是的
请务必注意,Stop 过渡元素对 中的 OR 没有影响。这些元素仅影响
的最终状态。例如,作业中的每个步骤都可能具有
状态为 but 以使作业的状态为 。Job
Job
BatchStatus
BatchStatus
ExitStatus
Steps
Job
Job
FAILED
COMPLETED
在步骤处结束
配置步骤结束会指示 a 以 的 a 停止。已完成且状态为 的 A 无法重新启动(框架会引发
a ).Job
BatchStatus
COMPLETED
Job
COMPLETED
JobInstanceAlreadyCompleteException
-
Java
-
XML
使用 Java 配置时,该方法用于此任务。方法
还允许使用可选参数,您可以使用该参数自定义 .如果未提供任何值,则默认情况下 为 匹配 .end
end
exitStatus
ExitStatus
Job
exitStatus
ExitStatus
COMPLETED
BatchStatus
使用 XML 配置时,您可以将 元素用于此任务。元素
还允许使用可选属性来自定义 .如果未给出任何属性,则默认情况下 将匹配 .end
end
exit-code
ExitStatus
Job
exit-code
ExitStatus
COMPLETED
BatchStatus
请考虑以下场景:如果失败,则使用 a of 和 of 停止,并且不会运行。
否则,执行将移动到 。请注意,如果失败,则 is not
可重启(因为状态为 )。step2
Job
BatchStatus
COMPLETED
ExitStatus
COMPLETED
step3
step3
step2
Job
COMPLETED
-
Java
-
XML
以下示例显示了 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 中的场景:
<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">
步骤失败
将步骤配置为在给定点失败会指示 a 停止并显示 of 。与 end 不同,a 的失败不会阻止 重新启动。Job
BatchStatus
FAILED
Job
Job
使用 XML 配置时,该元素还允许使用可选属性来自定义 .如果未给出任何属性,则默认情况下 将匹配 .fail
exit-code
ExitStatus
Job
exit-code
ExitStatus
FAILED
BatchStatus
请考虑以下场景:如果失败,则带有 a of 和 of 和 does not 的停止点
执行。否则,执行将移动到 。此外,如果失败并重新启动 ,则执行将在 上再次开始。step2
Job
BatchStatus
FAILED
ExitStatus
EARLY TERMINATION
step3
step3
step2
Job
step2
-
Java
-
XML
以下示例显示了 Java 中的场景:
@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 中的场景:
<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">
在给定步骤停止作业
将作业配置为在特定步骤停止会指示 a 停止 of 。停止 可以在处理中提供临时中断,
以便操作员可以在重新启动 .Job
BatchStatus
STOPPED
Job
Job
-
Java
-
XML
使用 Java 配置时,该方法需要一个属性
,该步骤指定在重新启动 Job 时应执行的步骤。stopAndRestart
restart
使用 XML 配置时,元素需要一个属性,该属性指定
重新启动 时应执行的步骤。stop
restart
Job
请考虑以下场景:如果以 结束,则作业
停止。重新启动后,执行将从 开始。step1
COMPLETE
step2
-
Java
-
XML
以下示例显示了 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 中的场景:
<step id="step1" parent="s1">
<stop on="COMPLETED" restart="step2"/>
</step>
<step id="step2" parent="s2"/>
编程流决策
在某些情况下,可能需要比 更多的信息来决定
下一步要执行的步骤。在这种情况下,a 可用于协助
在 decision 中,如下例所示:ExitStatus
JobExecutionDecider
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
-
XML
在下面的示例中,将传递一个实现
直接调用:JobExecutionDecider
next
@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();
}
在以下示例作业配置中,a 指定要用作
以及所有过渡:decision
<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"/>
拆分流
到目前为止描述的每个场景都涉及 a,它在
时间以线性方式。除了这种典型的样式之外, Spring Batch 还允许
对于要配置并行流的作业。Job
-
Java
-
XML
基于 Java 的配置允许您通过提供的生成器配置拆分。由于
以下示例显示,该元素包含一个或多个元素,其中
可以定义整个单独的流。元素还可以包含任何
前面讨论过 transition 元素,例如 attribute 或 、 、 或 元素。split
flow
split
next
next
end
fail
@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 命名空间允许您使用元素。如下例所示,
该元素包含一个或多个元素,其中整个单独的流可以
被定义。元素还可以包含前面讨论的任何过渡
元素,例如属性或 、 、 或 元素。split
split
flow
split
next
next
end
fail
<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"/>
外部化流程定义和作业之间的依赖关系
作业中的一部分流可以外部化为单独的 bean 定义,然后 重复使用。有两种方法可以做到这一点。第一种是将流声明为 引用到其他地方定义的 one。
-
Java
-
XML
下面的 Java 示例演示如何将流声明为对定义的流的引用 别处:
@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 示例演示如何将流声明为对定义的流的引用 别处:
<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>
定义外部流的效果(如前面的示例所示)是将 从外部流入作业的步骤,就像它们已内联声明一样。在 这样,许多 Job 可以引用相同的模板流,并将此类模板组合成 不同的逻辑流。这也是将 个人流动。
外部化流的另一种形式是使用 .A 与 a 类似,但实际上为
指定的流。JobStep
JobStep
FlowStep
-
Java
-
XML
以下示例显示了 Java 中的 a 示例:JobStep
@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 中的 a 示例:JobStep
<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>
作业参数提取器是一种策略,用于确定
的 被 转换为 为 的 运行 的。的
当您希望使用一些更精细的选项来监控和报告
作业和步骤。使用通常也是对这个问题的一个很好的回答:“我怎么做
在作业之间创建依赖关系?这是将大型系统分解为
更小的模块并控制作业流。ExecutionContext
Step
JobParameters
Job
JobStep
JobStep