跳到主要内容
版本:6.0.2

配置作业

DeepSeek V3 中英对照 Configuring a Job

Job 接口有多种实现方式。不过,这些实现都封装在提供的构建器(用于 Java 配置)或 XML 命名空间(用于基于 XML 的配置)之后。以下示例展示了 Java 和 XML 两种配置方式:

@Bean
public Job footballJob(JobRepository jobRepository) {
return new JobBuilder("footballJob", jobRepository)
.start(playerLoad())
.next(gameLoad())
.next(playerSummarization())
.build();
}

一个 Job(以及通常其中的任何 Step)都需要一个 JobRepository

前面的示例展示了一个由三个 Step 实例组成的 Job。与作业相关的构建器还可以包含其他元素,以帮助实现并行化(Split)、声明式流程控制(Decision)以及流程定义的外部化(Flow)。

可重启性

执行批处理作业时的一个关键问题涉及 Job 重启时的行为。如果特定 JobInstance 已存在对应的 JobExecution,则启动该 Job 将被视为“重启”。理想情况下,所有作业都应能从上次中断处继续执行,但在某些场景下这是无法实现的。在这种情况下,完全由开发人员负责确保创建新的 JobInstance 不过,Spring Batch 确实提供了一些帮助。如果某个 Job 不应被重启,而应始终作为新 JobInstance 的一部分运行,您可以将 restartable 属性设置为 false

以下示例展示了如何在 Java 中将 restartable 字段设置为 false

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

换句话说,将 restartable 设置为 false 意味着“此 Job 不支持重新启动”。重启一个不可重启的 Job 会导致抛出 JobRestartException。以下 Junit 代码会引发该异常:

Job job = new SimpleJob();
job.setRestartable(false);

JobParameters jobParameters = new JobParameters();

JobExecution firstExecution = jobRepository.createJobExecution(job, jobParameters);
jobRepository.saveOrUpdate(firstExecution);

try {
jobRepository.createJobExecution(job, jobParameters);
fail();
}
catch (JobRestartException e) {
// expected
}

首次为非可重启作业创建 JobExecution 的尝试不会引发问题。然而,第二次尝试会抛出 JobRestartException

拦截作业执行

Job 的执行过程中,能够获知其生命周期中的各种事件,以便运行自定义代码,这通常很有用。SimpleJob 通过在适当的时机调用 JobListener 来实现这一功能:

public interface JobExecutionListener {

void beforeJob(JobExecution jobExecution);

void afterJob(JobExecution jobExecution);
}

你可以通过为作业设置监听器,将 JobListeners 添加到 SimpleJob 中。

以下示例展示了如何向 Java 作业定义添加监听器方法:

@Bean
public Job footballJob(JobRepository jobRepository) {
return new JobBuilder("footballJob", jobRepository)
.listener(sampleListener())
...
.build();
}

请注意,无论 Job 成功还是失败,都会调用 afterJob 方法。如果需要判断成功或失败,可以从 JobExecution 中获取相关信息:

public void afterJob(JobExecution jobExecution){
if (jobExecution.getStatus() == BatchStatus.COMPLETED ) {
//job success
}
else if (jobExecution.getStatus() == BatchStatus.FAILED) {
//job failure
}
}

该接口对应的注解为:

  • @BeforeJob

  • @AfterJob

继承父作业

如果一组作业具有相似但不完全相同的配置,定义一个“父”Job可能会有所帮助,具体的Job实例可以从该父作业继承属性。类似于Java中的类继承,一个“子”Job会将其元素和属性与父作业的相结合。

在下面的示例中,baseJob 是一个抽象的 Job 定义,它只定义了一个监听器列表。而 Job (job1) 是一个具体的定义,它继承了 baseJob 的监听器列表,并将其与自身的监听器列表合并,从而产生了一个包含两个监听器和一个 Step (step1) 的 Job

<job id="baseJob" abstract="true">
<listeners>
<listener ref="listenerOne"/>
</listeners>
</job>

<job id="job1" parent="baseJob">
<step id="step1" parent="standaloneStep"/>

<listeners merge="true">
<listener ref="listenerTwo"/>
</listeners>
</job>

有关更多详细信息,请参阅从父步骤继承部分。

JobParametersValidator

在 XML 命名空间中声明的作业或使用 AbstractJob 的任何子类,可以选择在运行时为作业参数声明一个验证器。例如,当你需要确保作业启动时包含所有必需参数时,这非常有用。你可以使用 DefaultJobParametersValidator 来约束简单必需参数和可选参数的组合。对于更复杂的约束,你可以自行实现该接口。

验证器的配置可以通过 Java 构建器实现:

@Bean
public Job job1(JobRepository jobRepository) {
return new JobBuilder("job1", jobRepository)
.validator(parametersValidator())
...
.build();
}