高级元数据使用

JobRegistry

JobRegistry 用于跟踪上下文中哪些作业可用,并可由 JobOperator 操作。它也适用于在应用程序上下文中集中收集作业,即使它们是在其他地方(例如,在子上下文)创建的。您还可以使用自定义 JobRegistry 实现来操作已注册作业的名称和其他属性。框架只提供了一个实现,该实现基于从作业名称到作业实例的简单映射,即 MapJobRegistry

  • Java

  • XML

使用 @EnableBatchProcessing 时,会为您提供一个 MapJobRegistry。以下示例展示了如何配置您自己的 JobRegistry

...
@Bean
public JobRegistry jobRegistry() throws Exception {
	return new MyCustomJobRegistry();
}
...

以下示例展示了如何为 XML 中定义的作业包含 JobRegistry

<bean id="jobRegistry" class="org.springframework.batch.core.configuration.support.MapJobRegistry" />

Spring Batch 提供的 MapJobRegistry 足够智能,可以自动填充应用程序上下文中所有作业。但是,如果您使用 JobRegistry 的自定义实现,则需要手动填充要通过作业操作器操作的作业。

JobParametersIncrementer

JobOperator 中的大多数方法都一目了然,您可以在接口的 Javadoc 中找到更详细的解释。但是,startNextInstance 方法值得注意。此方法始终启动 Job 的新实例。如果 JobExecution 中存在严重问题并且需要从头开始重新启动 Job,这会非常有用。与 JobLauncher(它需要一个触发新 JobInstance 的新 JobParameters 对象)不同,如果参数与任何以前的参数集不同,startNextInstance 方法使用绑定到 JobJobParametersIncrementer 来强制 Job 到一个新的实例

public interface JobParametersIncrementer {

    JobParameters getNext(JobParameters parameters);

}

JobParametersIncrementer 的契约是,给定一个 JobParameters 对象,它通过递增其中可能包含的任何必要值来返回“下一个”JobParameters 对象。此策略很有用,因为框架无法知道对 JobParameters 的哪些更改使其成为“下一个”实例。例如,如果 JobParameters 中唯一的值是日期,并且应该创建下一个实例,那么该值应该增加一天还是一周(例如,如果作业是每周运行的)?同样,对于任何有助于识别 Job 的数值也可以这样说,如下例所示

public class SampleIncrementer implements JobParametersIncrementer {

    public JobParameters getNext(JobParameters parameters) {
        if (parameters==null || parameters.isEmpty()) {
            return new JobParametersBuilder().addLong("run.id", 1L).toJobParameters();
        }
        long id = parameters.getLong("run.id",1L) + 1;
        return new JobParametersBuilder().addLong("run.id", id).toJobParameters();
    }
}

在此示例中,键为 run.id 的值用于区分 JobInstances。如果传入的 JobParameters 为 null,则可以假定该 Job 从未运行过,因此可以返回其初始状态。但是,如果不是,则获取旧值,将其递增 1,然后返回。

  • Java

  • XML

对于用 Java 定义的作业,您可以通过构建器中提供的 incrementer 方法将增量器与 Job 相关联,如下所示

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

对于在 XML 中定义的作业,您可以通过命名空间中的 incrementer 属性将增量器与 Job 相关联,如下所示

<job id="footballJob" incrementer="sampleIncrementer">
    ...
</job>

停止作业

JobOperator 最常见的用例之一是优雅地停止作业

Set<Long> executions = jobOperator.getRunningExecutions("sampleJob");
jobOperator.stop(executions.iterator().next());

关闭不是立即的,因为无法强制立即关闭,特别是如果执行当前在开发人员代码中,而框架无法控制这些代码,例如业务服务。但是,一旦控制权返回给框架,它会将当前 StepExecution 的状态设置为 BatchStatus.STOPPED,保存它,并在完成之前对 JobExecution 执行相同的操作。

处理外部中断信号

从 v6.0+ 开始,Spring Batch 提供了一个 JobExecutionShutdownHook,您可以将其附加到 JVM 运行时,以拦截外部中断信号并优雅地停止作业执行

Thread springBatchHook = new JobExecutionShutdownHook(jobExecution, jobOperator);
Runtime.getRuntime().addShutdownHook(springBatchHook);

JobExecutionShutdownHook 需要跟踪作业执行,以及对将用于停止执行的作业操作器的引用。

恢复作业

如果未正确执行优雅关闭(即 JVM 突然关闭),Spring Batch 将无法正确更新执行状态以重新启动失败的作业执行。在这种情况下,作业执行将保持在 STARTED 状态,该状态不可重新启动。在这种情况下,可以使用 JobOperator API 恢复此类作业执行

JobExecution jobExecution = ...; // get the job execution to recover
jobOperator.recover(jobExecution);
jobOperator.restart(jobExecution);

中止作业

状态为 FAILED 的作业执行可以重新启动(如果 Job 可重新启动)。状态为 ABANDONED 的作业执行不能由框架重新启动。ABANDONED 状态也用于步骤执行中,以将其标记为在重新启动的作业执行中可跳过。如果作业正在运行并遇到在之前失败的作业执行中标记为 ABANDONED 的步骤,它将继续执行下一个步骤(由作业流定义和步骤执行退出状态确定)。

如果进程死亡(kill -9 或服务器故障),作业当然没有运行,但 JobRepository 无法知道,因为在进程死亡之前没有人告诉它。您必须手动告知它,您知道执行要么失败,要么应该被视为中止(将其状态更改为 FAILEDABANDONED)。这是一个业务决策,无法自动化。仅当可重新启动且您知道重新启动数据有效时,才将状态更改为 FAILED

© . This site is unofficial and not affiliated with VMware.