此版本仍在开发中,尚不被认为是稳定的。对于最新的稳定版本,请使用 Spring Batch 文档 5.2.2! |
控制步骤流
随着在拥有的工作中将步骤组合在一起的能力,需要能够
以控制作业如何从一个步骤“流动”到另一个步骤。一个Step
不
必然意味着Job
应该失败。此外,可能有不止一种类型
的“成功”决定了哪个Step
接下来应该执行。取决于
组Steps
配置后,某些步骤甚至可能根本无法处理。
流定义中的步骤 Bean 方法代理
步骤实例在流定义中必须是唯一的。当一个步骤在流定义中有多个结果时,
将步骤的同一实例传递给流定义方法 ( 在以下示例中,步骤作为参数注入到流或作业 Bean 定义方法中。这种依赖注入样式保证了流定义中步骤的唯一性。
但是,如果流是通过调用步骤定义方法来定义的,则 有关 Spring Framework 中 bean 方法代理的更多详细信息,请参阅使用 @Configuration 注释部分。 |
顺序流
最简单的流场景是所有步骤按顺序执行的作业,如 下图显示:

这可以通过使用next
在step
.
-
Java
-
XML
以下示例演示如何使用next()
Java 中的方法:
@Bean
public Job job(JobRepository jobRepository, Step stepA, Step stepB, Step stepC) {
return new JobBuilder("job", jobRepository)
.start(stepA)
.next(stepB)
.next(stepC)
.build();
}
以下示例演示如何使用next
XML 中的属性:
<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
fails 和stepB
不执行。
使用 Spring Batch XML 命名空间时,配置中列出的第一步始终是由Job .其他步骤元素的顺序不会
重要,但第一步必须始终出现在 XML 中的第一位。 |
条件流
在前面的示例中,只有两种可能性:
-
这
step
成功了,接下来step
应该执行。 -
这
step
失败,因此,job
应该失败。
在许多情况下,这可能就足够了。但是,如果
失败step
应该触发不同的step
,而不是造成失败?这
下图显示了这样的流:

-
Java
-
XML
Java API 提供了一组流畅的方法,可让您指定流和要执行的作
当一个步骤失败时。以下示例演示如何指定一个步骤 (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 命名空间允许您定义转换
步骤元素中的元素。其中一种过渡是next
元素。像next
属性,则next
元素告诉Job
哪Step
自
执行 next。但是,与属性不同的是,任意数量的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 配置时,on
属性使用简单的
模式匹配方案以匹配ExitStatus
执行Step
.
模式中只允许两个特殊字符:
-
*
匹配零个或多个字符 -
?
恰好匹配一个字符
例如c*t
比赛cat
和count
而c?t
比赛cat
但不是count
.
虽然Step
,如果Step
执行结果为ExitStatus
未被元素覆盖的,则
framework 抛出异常,并且Job
失败。框架自动排序
从最具体到最不具体的过渡。这意味着,即使订购
被换成stepA
在前面的示例中,一个ExitStatus
之FAILED
还是会去
自stepC
.
批处理状态与退出状态
配置Job
对于条件流,了解
区别BatchStatus
和ExitStatus
.BatchStatus
是一个枚举,其中
是两者的属性JobExecution
和StepExecution
并被框架用于
记录Job
或Step
.它可以是以下值之一:COMPLETED
,STARTING
,STARTED
,STOPPING
,STOPPED
,FAILED
,ABANDONED
或UNKNOWN
.其中大多数是不言自明的:COMPLETED
是步骤时设置的状态
或作业已成功完成,FAILED
失败时设置,依此类推。
-
Java
-
XML
以下示例包含on
元素:
...
.from(stepA).on("FAILED").to(stepB)
...
以下示例包含next
元素:
<next on="FAILED" to="stepB" />
乍一看,似乎on
引用BatchStatus
的Step
自
它所属的。但是,它实际上引用了ExitStatus
的Step
.作为
顾名思义ExitStatus
表示Step
在它完成执行后。
-
Java
-
XML
使用 Java 配置时,on()
如前述所示的方法
Java 配置示例引用了ExitStatus
.
更具体地说,当使用 XML 配置时,next
元素显示在
前面的 XML 配置示例引用了ExitStatus
.
在英语中,它说:“如果退出代码为 FAILED,则转到步骤 B”。默认情况下,出口
code 始终与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
failed,在这种情况下,作业应该失败。 -
这
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;
}
}
}
前面的代码是StepExecutionListener
首先检查以确保Step
是
成功,然后检查StepExecution
高于
0. 如果同时满足这两个条件,则新的ExitStatus
退出代码为COMPLETED WITH SKIPS
被返回。
配置停止
经过讨论BatchStatus
和ExitStatus
,
人们可能想知道BatchStatus
和ExitStatus
确定为Job
.
虽然这些状态是为Step
通过执行的代码,
状态Job
根据配置确定。
到目前为止,所有讨论的作业配置都至少有一个最终结果Step
跟
没有过渡。
-
Java
-
XML
在下面的 Java 示例中,在step
执行,则Job
结束:
@Bean
public Job job(JobRepository jobRepository, Step step1) {
return new JobBuilder("job", jobRepository)
.start(step1)
.build();
}
在以下 XML 示例中,在step
执行,则Job
结束:
<step id="step1" parent="s3"/>
如果未为Step
,则Job
定义为
遵循:
-
如果
Step
结尾为ExitStatus
之FAILED
这BatchStatus
和ExitStatus
之 这Job
都是FAILED
. -
否则,
BatchStatus
和ExitStatus
的Job
都是COMPLETED
.
虽然这种终止批处理作业的方法对于某些批处理作业(例如
简单的顺序步骤作业,可能需要自定义定义的作业停止场景。为
为此,Spring Batch 提供了三个过渡元素来阻止Job
(在
除了next
元素我们之前讨论过的)。
这些停止元素中的每一个都会停止一个Job
使用特定的BatchStatus
.是的
重要的是要注意,停止过渡元素对BatchStatus
或ExitStatus
任何Steps
在Job
.这些元素仅影响
的最终状态Job
.例如,作业中的每个步骤都可能具有
状态为FAILED
但要使作业的状态为COMPLETED
.
在步骤结束
配置步骤结束指示Job
以BatchStatus
之COMPLETED
.一个Job
已结束状态为COMPLETED
无法重新启动(框架抛出
一个JobInstanceAlreadyCompleteException
).
-
Java
-
XML
使用 Java 配置时,end
方法用于此任务。这end
方法
还允许可选的exitStatus
参数,可用于自定义ExitStatus
的Job
.如果没有exitStatus
value 时,则ExitStatus
是COMPLETED
默认情况下,要匹配BatchStatus
.
使用 XML 配置时,您可以使用end
元素。这end
元素
还允许可选的exit-code
属性,您可以使用该属性来自定义ExitStatus
的Job
.如果没有exit-code
属性,则ExitStatus
是COMPLETED
默认情况下,要匹配BatchStatus
.
考虑以下场景:如果step2
fails,则Job
以BatchStatus
之COMPLETED
和ExitStatus
之COMPLETED
和step3
不运行。
否则,执行将移至step3
.请注意,如果step2
fails,则Job
莫
restartable(因为状态为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">
步骤失败
将步骤配置为在给定点失败会指示Job
以BatchStatus
之FAILED
.与 end 不同,失败Job
不会阻止Job
从重新启动。
使用 XML 配置时,fail
元素还允许可选的exit-code
属性,可用于自定义ExitStatus
的Job
.如果没有exit-code
属性,则ExitStatus
是FAILED
默认情况下,要匹配BatchStatus
.
考虑以下场景:如果step2
fails,则Job
以BatchStatus
之FAILED
和ExitStatus
之EARLY TERMINATION
和step3
不
执行。否则,执行将移至step3
.此外,如果step2
fails 和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">
在给定步骤停止作业
将作业配置为在特定步骤停止会指示Job
以BatchStatus
之STOPPED
.停止Job
可以提供加工的暂时中断,
以便操作员可以在重新启动Job
.
-
Java
-
XML
使用 Java 配置时,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"/>
程序化流程决策
在某些情况下,信息比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
使用 Java 配置时调用:
@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();
}
在以下示例作业配置中,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"/>
拆分流
到目前为止,描述的每个场景都涉及Job
以
线性方式的时间。除了这种典型的样式外,Spring Batch 还允许
用于配置具有并行流的作业。
-
Java
-
XML
基于 Java 的配置允许您通过提供的构建器配置拆分。作为
以下示例显示,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 定义进行外部化,然后 重复使用。有两种方法可以做到这一点。第一种是将流声明为 引用其他地方定义的。
-
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>
如前面的示例所示,定义外部流的效果是将外部流中的步骤插入到作业中,就像它们已内联声明一样。 在 这样,许多作业可以引用相同的模板流,并将这些模板组合成不同的逻辑流。这也是分离集成测试的好方法各个流。
外部化流的另一种形式是使用JobStep
.一个JobStep
类似于FlowStep
但实际上为指定的流程创建并启动单独的作业执行。
-
Java
-
XML
以下示例显示了JobStep
在 Java 中:
@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;
}
以下示例如何以JobStep
在 XML 中:
<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
也往往是对这个问题的很好的回答:“我该如何
在工作之间建立依赖关系?这是将大型系统分解为以下内容的好方法
更小的模块并控制作业流程。