配置 Job

`Job` 接口有多种实现。然而,这些实现被抽象在提供的构建器(用于 Java 配置)或 XML 命名空间(用于基于 XML 的配置)之后。以下示例展示了 Java 和 XML 配置

  • Java

  • XML

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

一个 `Job`(通常包括其中的任何 `Step`)需要一个 `JobRepository`。`JobRepository` 的配置通过 `Java 配置` 来处理。

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

`Job` 接口有多种实现。然而,命名空间抽象了配置的差异。它只有三个必需的依赖:一个名称、`JobRepository` 和 `Step` 实例列表。以下示例创建了一个 `footballJob`

<job id="footballJob">
    <step id="playerload"          parent="s1" next="gameLoad"/>
    <step id="gameLoad"            parent="s2" next="playerSummarization"/>
    <step id="playerSummarization" parent="s3"/>
</job>

前面的示例使用父 Bean 定义来创建 Step。有关内联声明特定 Step 详细信息的更多选项,请参阅 step configuration 部分。XML 命名空间默认引用 `id` 为 `jobRepository` 的仓库,这是一个合理的默认值。但是,你可以显式覆盖此默认值

<job id="footballJob" job-repository="specialRepository">
    <step id="playerload"          parent="s1" next="gameLoad"/>
    <step id="gameLoad"            parent="s3" next="playerSummarization"/>
    <step id="playerSummarization" parent="s3"/>
</job>

除了 Step 之外,Job 配置还可以包含其他有助于并行化 (`<split>`)、声明式流程控制 (`<decision>`) 和流程定义外部化 (`<flow/>`) 的元素。

可重启性

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

  • Java

  • XML

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

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

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

XML 配置
<job id="footballJob" restartable="false">
    ...
</job>

换句话说,将 `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
}

首次为不可重启的 Job 创建 `JobExecution` 不会导致问题。然而,第二次尝试会抛出 `JobRestartException` 异常。

拦截 Job 执行

在 `Job` 执行过程中,可能需要在其生命周期的各个事件发生时收到通知,以便运行自定义代码。`SimpleJob` 通过在适当时候调用 `JobListener` 来实现这一点

public interface JobExecutionListener {

    void beforeJob(JobExecution jobExecution);

    void afterJob(JobExecution jobExecution);
}

你可以通过在 Job 上设置监听器来向 `SimpleJob` 添加 `JobListeners`。

  • Java

  • XML

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

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

以下示例展示了如何向 XML Job 定义添加监听器元素

XML 配置
<job id="footballJob">
    <step id="playerload"          parent="s1" next="gameLoad"/>
    <step id="gameLoad"            parent="s2" next="playerSummarization"/>
    <step id="playerSummarization" parent="s3"/>
    <listeners>
        <listener ref="sampleListener"/>
    </listeners>
</job>

请注意,无论 `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 共享相似但不完全相同的配置,则可以定义一个“父” `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>

有关更详细的信息,请参阅 Inheriting from a Parent Step 部分。

JobParametersValidator

在 XML 命名空间中声明的 Job 或使用 `AbstractJob` 的任何子类的 Job 都可以选择在运行时声明 Job 参数的验证器。当例如需要断言 Job 以所有强制参数启动时,这非常有用。有一个 `DefaultJobParametersValidator`,你可以使用它来约束简单的强制和可选参数的组合。对于更复杂的约束,你可以自己实现该接口。

  • Java

  • XML

验证器的配置通过 Java 构建器支持

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

验证器的配置通过 XML 命名空间中的 Job 子元素支持,如下例所示

<job id="job1" parent="baseJob3">
    <step id="step1" parent="standaloneStep"/>
    <validator ref="parametersValidator"/>
</job>

你可以将验证器指定为引用(如前面所示),或作为 `beans` 命名空间中的嵌套 bean 定义。