此版本仍在开发中,尚不被认为是稳定的。对于最新的稳定版本,请使用 Spring Batch 文档 5.2.2spring-doc.cadn.net.cn

控制步骤流

随着在拥有的工作中将步骤组合在一起的能力,需要能够 以控制作业如何从一个步骤“流动”到另一个步骤。一个Step不 必然意味着Job应该失败。此外,可能有不止一种类型 的“成功”决定了哪个Step接下来应该执行。取决于 组Steps配置后,某些步骤甚至可能根本无法处理。spring-doc.cadn.net.cn

流定义中的步骤 Bean 方法代理

步骤实例在流定义中必须是唯一的。当一个步骤在流定义中有多个结果时, 将步骤的同一实例传递给流定义方法 (start,from等)。 否则,流执行可能会出现意外行为。spring-doc.cadn.net.cn

在以下示例中,步骤作为参数注入到流或作业 Bean 定义方法中。这种依赖注入样式保证了流定义中步骤的唯一性。 但是,如果流是通过调用步骤定义方法来定义的,则@Bean,则如果禁用了 bean 方法代理(即@Configuration(proxyBeanMethods = false)). 如果首选 bean 间注入样式,则必须启用 bean 方法代理。spring-doc.cadn.net.cn

有关 Spring Framework 中 bean 方法代理的更多详细信息,请参阅使用 @Configuration 注释部分。spring-doc.cadn.net.cn

顺序流

最简单的流场景是所有步骤按顺序执行的作业,如 下图显示:spring-doc.cadn.net.cn

顺序流
图 1.顺序流

这可以通过使用nextstep.spring-doc.cadn.net.cn

以下示例演示如何使用next()Java 中的方法:spring-doc.cadn.net.cn

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();
}

以下示例演示如何使用nextXML 中的属性:spring-doc.cadn.net.cn

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失败 整个Jobfails 和stepB不执行。spring-doc.cadn.net.cn

使用 Spring Batch XML 命名空间时,配置中列出的第一步始终是由Job.其他步骤元素的顺序不会 重要,但第一步必须始终出现在 XML 中的第一位。

条件流

在前面的示例中,只有两种可能性:spring-doc.cadn.net.cn

  1. step成功了,接下来step应该执行。spring-doc.cadn.net.cn

  2. step失败,因此,job应该失败。spring-doc.cadn.net.cn

在许多情况下,这可能就足够了。但是,如果 失败step应该触发不同的step,而不是造成失败?这 下图显示了这样的流:spring-doc.cadn.net.cn

条件流
图 2.条件流

Java API 提供了一组流畅的方法,可让您指定流和要执行的作 当一个步骤失败时。以下示例演示如何指定一个步骤 (stepA),然后 继续执行两个不同步骤(stepBstepC),取决于是否stepA成功:spring-doc.cadn.net.cn

Java 配置
@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元素告诉JobStep自 执行 next。但是,与属性不同的是,任意数量的next元素允许在 给定的Step,并且在失败的情况下没有默认行为。这意味着,如果 过渡元素,则Step过渡必须是 明确定义。另请注意,单个步骤不能同时具有next属性和 一个transition元素。spring-doc.cadn.net.cn

next元素指定要匹配的模式和接下来要执行的步骤,如 以下示例显示:spring-doc.cadn.net.cn

XML 配置
<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 配置时,on()方法使用简单的模式匹配方案来 匹配ExitStatus执行Step.spring-doc.cadn.net.cn

使用 XML 配置时,on属性使用简单的 模式匹配方案以匹配ExitStatus执行Step.spring-doc.cadn.net.cn

模式中只允许两个特殊字符:spring-doc.cadn.net.cn

例如c*t比赛catcountc?t比赛cat但不是count.spring-doc.cadn.net.cn

虽然Step,如果Step执行结果为ExitStatus未被元素覆盖的,则 framework 抛出异常,并且Job失败。框架自动排序 从最具体到最不具体的过渡。这意味着,即使订购 被换成stepA在前面的示例中,一个ExitStatusFAILED还是会去 自stepC.spring-doc.cadn.net.cn

批处理状态与退出状态

配置Job对于条件流,了解 区别BatchStatusExitStatus.BatchStatus是一个枚举,其中 是两者的属性JobExecutionStepExecution并被框架用于 记录JobStep.它可以是以下值之一:COMPLETED,STARTING,STARTED,STOPPING,STOPPED,FAILED,ABANDONEDUNKNOWN.其中大多数是不言自明的:COMPLETED是步骤时设置的状态 或作业已成功完成,FAILED失败时设置,依此类推。spring-doc.cadn.net.cn

以下示例包含on元素:spring-doc.cadn.net.cn

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

以下示例包含next元素:spring-doc.cadn.net.cn

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

乍一看,似乎on引用BatchStatusStep自 它所属的。但是,它实际上引用了ExitStatusStep.作为 顾名思义ExitStatus表示Step在它完成执行后。spring-doc.cadn.net.cn

使用 Java 配置时,on()如前述所示的方法 Java 配置示例引用了ExitStatus.spring-doc.cadn.net.cn

更具体地说,当使用 XML 配置时,next元素显示在 前面的 XML 配置示例引用了ExitStatus.spring-doc.cadn.net.cn

在英语中,它说:“如果退出代码为 FAILED,则转到步骤 B”。默认情况下,出口 code 始终与BatchStatus对于Step,这就是为什么前面的条目 工程。但是,如果退出代码需要不同怎么办?一个很好的例子来自 示例项目中的跳过示例作业:spring-doc.cadn.net.cn

以下示例显示了如何在 Java 中使用不同的退出代码:spring-doc.cadn.net.cn

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 中的不同退出代码:spring-doc.cadn.net.cn

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

step1有三种可能:spring-doc.cadn.net.cn

上述配置有效。但是,需要根据以下内容更改退出代码 跳过记录的执行条件,如以下示例所示:spring-doc.cadn.net.cn

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被返回。spring-doc.cadn.net.cn

配置停止

经过讨论BatchStatusExitStatus, 人们可能想知道BatchStatusExitStatus确定为Job. 虽然这些状态是为Step通过执行的代码, 状态Job根据配置确定。spring-doc.cadn.net.cn

到目前为止,所有讨论的作业配置都至少有一个最终结果Step跟 没有过渡。spring-doc.cadn.net.cn

在下面的 Java 示例中,在step执行,则Job结束:spring-doc.cadn.net.cn

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

在以下 XML 示例中,在step执行,则Job结束:spring-doc.cadn.net.cn

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

如果未为Step,则Job定义为 遵循:spring-doc.cadn.net.cn

虽然这种终止批处理作业的方法对于某些批处理作业(例如 简单的顺序步骤作业,可能需要自定义定义的作业停止场景。为 为此,Spring Batch 提供了三个过渡元素来阻止Job(在 除了next元素我们之前讨论过的)。 这些停止元素中的每一个都会停止一个Job使用特定的BatchStatus.是的 重要的是要注意,停止过渡元素对BatchStatusExitStatus任何StepsJob.这些元素仅影响 的最终状态Job.例如,作业中的每个步骤都可能具有 状态为FAILED但要使作业的状态为COMPLETED.spring-doc.cadn.net.cn

在步骤结束

配置步骤结束指示JobBatchStatusCOMPLETED.一个Job已结束状态为COMPLETED无法重新启动(框架抛出 一个JobInstanceAlreadyCompleteException).spring-doc.cadn.net.cn

使用 Java 配置时,end方法用于此任务。这end方法 还允许可选的exitStatus参数,可用于自定义ExitStatusJob.如果没有exitStatusvalue 时,则ExitStatusCOMPLETED默认情况下,要匹配BatchStatus.spring-doc.cadn.net.cn

使用 XML 配置时,您可以使用end元素。这end元素 还允许可选的exit-code属性,您可以使用该属性来自定义ExitStatusJob.如果没有exit-code属性,则ExitStatusCOMPLETED默认情况下,要匹配BatchStatus.spring-doc.cadn.net.cn

考虑以下场景:如果step2fails,则JobBatchStatusCOMPLETEDExitStatusCOMPLETEDstep3不运行。 否则,执行将移至step3.请注意,如果step2fails,则Job莫 restartable(因为状态为COMPLETED).spring-doc.cadn.net.cn

以下示例显示了 Java 中的场景:spring-doc.cadn.net.cn

@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 中的方案:spring-doc.cadn.net.cn

<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">

步骤失败

将步骤配置为在给定点失败会指示JobBatchStatusFAILED.与 end 不同,失败Job不会阻止Job从重新启动。spring-doc.cadn.net.cn

使用 XML 配置时,fail元素还允许可选的exit-code属性,可用于自定义ExitStatusJob.如果没有exit-code属性,则ExitStatusFAILED默认情况下,要匹配BatchStatus.spring-doc.cadn.net.cn

考虑以下场景:如果step2fails,则JobBatchStatusFAILEDExitStatusEARLY TERMINATIONstep3不 执行。否则,执行将移至step3.此外,如果step2fails 和Job重新启动时,执行将重新开始step2.spring-doc.cadn.net.cn

以下示例显示了 Java 中的场景:spring-doc.cadn.net.cn

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 中的方案:spring-doc.cadn.net.cn

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">

在给定步骤停止作业

将作业配置为在特定步骤停止会指示JobBatchStatusSTOPPED.停止Job可以提供加工的暂时中断, 以便操作员可以在重新启动Job.spring-doc.cadn.net.cn

使用 Java 配置时,stopAndRestart方法需要一个restart属性 指定重新启动作业时应开始执行的步骤。spring-doc.cadn.net.cn

使用 XML 配置时,stop元素需要一个restart指定 当Job将重新启动。spring-doc.cadn.net.cn

考虑以下场景:如果step1饰面COMPLETE,则作业 停止。重新启动后,执行开始step2.spring-doc.cadn.net.cn

以下示例显示了 Java 中的场景:spring-doc.cadn.net.cn

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

以下列表显示了 XML 中的方案:spring-doc.cadn.net.cn

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

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

程序化流程决策

在某些情况下,信息比ExitStatus可能需要决定接下来要执行哪个步骤。在这种情况下,一个JobExecutionDecider可用于协助在决策中,如以下示例所示:spring-doc.cadn.net.cn

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);
    }
}

在以下示例中,实现JobExecutionDecider被传递给直接传递给next使用 Java 配置时调用:spring-doc.cadn.net.cn

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指定要用作的决策器以及所有过渡:spring-doc.cadn.net.cn

XML 配置
<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 还允许 用于配置具有并行流的作业。spring-doc.cadn.net.cn

基于 Java 的配置允许您通过提供的构建器配置拆分。作为 以下示例显示,split元素包含一个或多个flow元素,其中 可以定义整个单独的流。一个split元素还可以包含任何 前面讨论过的过渡元素,例如next属性或next,endfail元素。spring-doc.cadn.net.cn

@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,endfail元素。spring-doc.cadn.net.cn

<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 定义进行外部化,然后 重复使用。有两种方法可以做到这一点。第一种是将流声明为 引用其他地方定义的。spring-doc.cadn.net.cn

以下 Java 示例演示如何将流声明为对已定义流的引用 别处:spring-doc.cadn.net.cn

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 示例演示如何将流声明为对已定义流的引用 别处:spring-doc.cadn.net.cn

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>

如前面的示例所示,定义外部流的效果是将外部流中的步骤插入到作业中,就像它们已内联声明一样。 在 这样,许多作业可以引用相同的模板流,并将这些模板组合成不同的逻辑流。这也是分离集成测试的好方法各个流。spring-doc.cadn.net.cn

外部化流的另一种形式是使用JobStep.一个JobStep类似于FlowStep但实际上为指定的流程创建并启动单独的作业执行。spring-doc.cadn.net.cn

以下示例显示了JobStep在 Java 中:spring-doc.cadn.net.cn

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 中:spring-doc.cadn.net.cn

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也往往是对这个问题的很好的回答:“我该如何 在工作之间建立依赖关系?这是将大型系统分解为以下内容的好方法 更小的模块并控制作业流程。spring-doc.cadn.net.cn