Batch 的领域语言

Batch 的域语言

对于任何有经验的批处理架构师来说,批处理的总体概念 Spring Batch 应该是熟悉和舒适的。有 “Jobs” 和 “Steps” 以及 开发人员提供的名为 和 的处理单元。然而 由于 Spring 模式、操作、模板、回调和惯用语,因此有 以下机会:ItemReaderItemWriterspring-doc.cn

  • 对明确关注点分离的依从性显著提高。spring-doc.cn

  • 清晰描述的架构层和作为接口提供的服务。spring-doc.cn

  • 简单的默认实现,允许快速采用和易于使用 开箱即用。spring-doc.cn

  • 显著增强了可扩展性。spring-doc.cn

下图是批处理参考体系结构的简化版本,该体系结构 已经使用了几十年。它概述了构成 batch processing 的 domain language 进行批处理。此体系结构框架是一个蓝图,它具有以下 已通过最近几代的数十年实施得到验证 平台(COBOL/Mainframe、C/Unix 和现在的 Java/anywhere)。JCL 和 COBOL 开发人员 可能和 C、C# 和 Java 开发人员一样熟悉这些概念。Spring Batch 提供了 layers、components 和 technical 的物理实现 服务常见于健壮、可维护的系统,用于解决 使用基础设施和扩展创建从简单到复杂的批处理应用程序 以满足非常复杂的加工需求。spring-doc.cn

图 2.1: 批量构造型
图 1.批量构造型

上图突出显示了构成 Spring Batch 中。Job 有一到多个步骤,每个步骤都只有一个 , 一个 ,和一个 。需要启动作业 (使用 ),并且需要存储有关当前正在运行的进程的元数据 (在 中)。ItemReaderItemProcessorItemWriterJobLauncherJobRepositoryspring-doc.cn

工作

本节介绍与批处理作业概念相关的构造型。A 是一个 封装整个批处理过程的实体。与其他 Spring 一样 projects 中,与 XML 配置文件或基于 Java 的 配置。此配置可称为 “job configuration”。但是,只是整个层次结构的顶部,如下图所示:JobJobJobspring-doc.cn

作业层次结构
图 2.作业层次结构

在 Spring Batch 中,a 只是实例的容器。它结合了多个 在逻辑上属于流中并允许配置属性的步骤 global 到所有步骤,例如可重启性。作业配置包含:JobStepspring-doc.cn

对于使用 Java 配置的用户,Spring Batch 提供了 Job 接口,它以类的形式创建一些标准 功能。当使用基于 java 的配置时,一个 builders 可用于实例化 ,如下所示 例:SimpleJobJobJobspring-doc.cn

@Bean
public Job footballJob() {
    return this.jobBuilderFactory.get("footballJob")
                     .start(playerLoad())
                     .next(gameLoad())
                     .next(playerSummarization())
                     .build();
}

对于那些使用 XML 配置的用户, Spring Batch 以类的形式提供了接口的默认实现,它创建了一些标准 功能。但是,批处理命名空间抽象化了 直接实例化它。相反,可以使用该元素,如 以下示例:JobSimpleJobJob<job>spring-doc.cn

<job id="footballJob">
    <step id="playerload" next="gameLoad"/>
    <step id="gameLoad" next="playerSummarization"/>
    <step id="playerSummarization"/>
</job>

JobInstance 实例

A 是指逻辑作业运行的概念。考虑一个批处理作业,该 应该在一天结束时运行一次,例如前面的 图。有一个 'EndOfDay' 作业,但 的每个单独运行都必须是 单独跟踪。对于此作业,每天有一个 logical。 例如,有 1 月 1 日运行、1 月 2 日运行,依此类推。如果 1 月 1 日 run 第一次失败,第二天再次运行,它仍然是 1 月 1 日的运行。 (通常,这也与它正在处理的数据相对应,即 1 月 第 1 次运行处理 1 月 1 日的数据)。因此,每个 API 都可以有多个 执行(本章稍后将更详细地讨论),并且仅 一个对应于特定和识别的罐头 在给定时间运行。JobInstanceJobJobJobInstanceJobInstanceJobExecutionJobInstanceJobJobParametersspring-doc.cn

a 的定义与要加载的数据完全无关。 如何加载数据完全取决于实现。为 例如,在 EndOfDay 场景中,数据上可能有一列指示 数据所属的“生效日期”或“计划日期”。所以,1 月 1 日运行 将仅加载第 1 次运行中的数据,而 1 月 2 日运行将仅使用 第二。因为这个决定可能是一个商业决策,所以它留给 自己决定。但是,使用相同的 API 可以确定 'state'(即 ,本章稍后将讨论) 使用以前的执行。使用 new 意味着 'start from beginning“,使用现有实例通常意味着”从您离开的地方开始” 关闭”。JobInstanceItemReaderItemReaderJobInstanceExecutionContextJobInstancespring-doc.cn

JobParameters (作业参数)

在讨论了它与约伯记的不同之后,自然而然地要问的问题 是:“一个人如何与另一个人区分开来?答案是: .对象包含一组用于启动批处理的参数 工作。它们可用于识别,甚至在运行期间用作参考数据,如 如下图所示:JobInstanceJobInstanceJobParametersJobParametersspring-doc.cn

作业参数
图 3.作业参数

在前面的示例中,有两个实例,一个用于 1 月 1 日,另一个用于 1 月 1 日 对于 January 2nd,实际上只有一个 ,但它有两个对象: 一个以 Job 参数 01-01-2017 启动,另一个以 参数为 01-02-2017。因此,合约可以定义为: = + 标识 .这允许开发人员有效地控制 a 的定义方式,因为他们控制传入的参数。JobJobParameterJobInstanceJobJobParametersJobInstancespring-doc.cn

并非所有作业参数都需要用于识别 .默认情况下,它们会这样做。但是,框架也允许提交 的 a 的参数对 .JobInstanceJobJobInstance

JobExecution (任务执行)

A 是指单次尝试运行 Job 的技术概念。一 执行可能以 failure 或 success 结束,但对应于给定的 除非执行成功完成,否则不会认为执行已完成。 以前面描述的 EndOfDay 为例,考虑一个 for 2017 年 1 月 1 日,第一次运行时失败。如果使用相同的 将作业参数标识为首次运行 (01-01-2017),则新的 IS 创建。但是,仍然只有一个 .JobExecutionJobInstanceJobJobInstanceJobExecutionJobInstancespring-doc.cn

a 定义什么是作业以及如何执行作业,a 是 Purely Organizational 对象将执行分组在一起,主要是为了启用正确的 restart semantics 的 Semantics 中。但是,A 是 实际发生在运行期间,并且包含更多必须控制的属性 和 persisted,如下表所示:JobJobInstanceJobExecutionspring-doc.cn

表 1.JobExecution 属性

财产spring-doc.cn

定义spring-doc.cn

地位spring-doc.cn

指示执行状态的对象。运行时,它是 。如果失败,则为 。如果完成 成功了,它是BatchStatusBatchStatus#STARTEDBatchStatus#FAILEDBatchStatus#COMPLETEDspring-doc.cn

startTime (开始时间)spring-doc.cn

A 表示开始执行时的当前系统时间。 如果作业尚未启动,则此字段为空。java.util.Datespring-doc.cn

结束时间spring-doc.cn

A 表示执行完成时的当前系统时间, 无论它是否成功。如果作业尚未 完成。java.util.Datespring-doc.cn

exitStatusspring-doc.cn

的 ,指示运行的结果。这是最重要的,因为它 包含返回给调用方的退出代码。有关更多详细信息,请参阅第 5 章。这 如果作业尚未完成,则字段为空。ExitStatusspring-doc.cn

创建时间spring-doc.cn

A 表示当前系统时间 首先持续存在。作业可能尚未启动(因此没有开始时间),但 它始终具有 createTime,这是管理 job level 的框架所必需的。java.util.DateJobExecutionExecutionContextsspring-doc.cn

lastUpdatedspring-doc.cn

A 表示上次保留 a 的时间。此字段 如果作业尚未启动,则为空。java.util.DateJobExecutionspring-doc.cn

executionContextspring-doc.cn

包含需要在 执行。spring-doc.cn

failureExceptions 异常spring-doc.cn

在执行 .这些可能很有用 如果在 失败期间遇到多个异常。JobJobspring-doc.cn

这些属性很重要,因为它们是持久的,可以完全用于 确定执行的状态。例如,如果 01-01 的 EndOfDay 作业为 在晚上 9:00 执行,在 9:30 失败,则在批处理中创建以下条目 元数据表:spring-doc.cn

表 2.BATCH_JOB_INSTANCE

JOB_INST_IDspring-doc.cn

JOB_NAMEspring-doc.cn

1spring-doc.cn

结束工作spring-doc.cn

表 3.BATCH_JOB_EXECUTION_PARAMS

JOB_EXECUTION_IDspring-doc.cn

TYPE_CDspring-doc.cn

KEY_NAMEspring-doc.cn

DATE_VALspring-doc.cn

识别spring-doc.cn

1spring-doc.cn

日期spring-doc.cn

附表。日期spring-doc.cn

2017-01-01spring-doc.cn

spring-doc.cn

表 4.BATCH_JOB_EXECUTION

JOB_EXEC_IDspring-doc.cn

JOB_INST_IDspring-doc.cn

START_TIMEspring-doc.cn

END_TIMEspring-doc.cn

地位spring-doc.cn

1spring-doc.cn

1spring-doc.cn

2017-01-01 21:00spring-doc.cn

2017-01-01 21:30spring-doc.cn

失败spring-doc.cn

为了清楚起见,可能已缩写或删除列名,并且 格式。

现在作业已失败,假设问题花了一整夜才出现 确定,因此 'Batch 窗口' 现在已关闭。进一步假设窗口 从晚上 9:00 开始,作业在 01-01 中再次启动,从中断处开始,然后 在 9:30 成功完成。因为现在是第二天,所以 01-02 作业必须为 运行,之后在 9:31 开始,并在正常时间完成 时间 10:30。没有要求在之后踢出一个 另一个,除非两个 Job 有可能尝试访问相同的数据, 导致数据库级别的锁定问题。这完全取决于调度程序 确定何时应运行 a。由于它们是独立的,因此 Spring Batch 不会尝试阻止它们并发运行。(尝试运行 same while another already is running 会导致 a 被抛出)。现在应该有一个额外的条目 在 AND 表中以及表中的两个额外条目中,如下表所示:JobInstanceJobJobInstancesJobInstanceJobExecutionAlreadyRunningExceptionJobInstanceJobParametersJobExecutionspring-doc.cn

表 5.BATCH_JOB_INSTANCE

JOB_INST_IDspring-doc.cn

JOB_NAMEspring-doc.cn

1spring-doc.cn

结束工作spring-doc.cn

2spring-doc.cn

结束工作spring-doc.cn

表 6.BATCH_JOB_EXECUTION_PARAMS

JOB_EXECUTION_IDspring-doc.cn

TYPE_CDspring-doc.cn

KEY_NAMEspring-doc.cn

DATE_VALspring-doc.cn

识别spring-doc.cn

1spring-doc.cn

日期spring-doc.cn

附表。日期spring-doc.cn

2017-01-01 00:00:00spring-doc.cn

spring-doc.cn

2spring-doc.cn

日期spring-doc.cn

附表。日期spring-doc.cn

2017-01-01 00:00:00spring-doc.cn

spring-doc.cn

3spring-doc.cn

日期spring-doc.cn

附表。日期spring-doc.cn

2017-01-02 00:00:00spring-doc.cn

spring-doc.cn

表 7.BATCH_JOB_EXECUTION

JOB_EXEC_IDspring-doc.cn

JOB_INST_IDspring-doc.cn

START_TIMEspring-doc.cn

END_TIMEspring-doc.cn

地位spring-doc.cn

1spring-doc.cn

1spring-doc.cn

2017-01-01 21:00spring-doc.cn

2017-01-01 21:30spring-doc.cn

失败spring-doc.cn

2spring-doc.cn

1spring-doc.cn

2017-01-02 21:00spring-doc.cn

2017-01-02 21:30spring-doc.cn

完成spring-doc.cn

3spring-doc.cn

2spring-doc.cn

2017-01-02 21:31spring-doc.cn

2017-01-02 22:29spring-doc.cn

完成spring-doc.cn

为了清楚起见,可能已缩写或删除列名,并且 格式。

A 是一个域对象,它封装了批处理的独立顺序阶段 工作。因此,每个 Job 都完全由一个或多个步骤组成。A 包含 定义和控制实际批处理所需的所有信息。这 必然是一个模糊的描述,因为任何给定的内容都位于 编写 .A 可以像 开发者的愿望。一个简单的可能会将数据从文件加载到数据库中, 需要很少或不需要代码(取决于使用的实现)。更复杂的应用程序可能具有复杂的业务规则,这些规则作为处理的一部分应用。如 其中 a 具有与 unique 关联的 individual ,如下图所示:StepStepStepJobStepStepStepJobStepStepExecutionJobExecutionspring-doc.cn

图 2.1.. 包含步骤的作业层次结构
图 4.包含步骤的作业层次结构

StepExecution 执行

A 表示执行 .每次运行 时都会创建一个新的 a,类似于 。但是,如果步骤失败 执行,因为该步骤在失败之前,则不会保留任何执行。只有在实际启动时才会创建 A。StepExecutionStepStepExecutionStepJobExecutionStepExecutionStepspring-doc.cn

Step执行由 class 的对象表示。每次执行 包含对其相应步骤的引用,并且与 Transaction 相关 数据,例如提交和回滚计数以及开始和结束时间。此外,每个步骤 execution 包含一个 ,其中包含开发人员需要 在批处理运行中保留,例如所需的统计信息或状态信息 重新启动。下表列出了 的属性 :StepExecutionJobExecutionExecutionContextStepExecutionspring-doc.cn

表 8.StepExecution 属性

财产spring-doc.cn

定义spring-doc.cn

地位spring-doc.cn

指示执行状态的对象。运行时, status 为 。如果失败,则状态为 。如果它 成功完成,则状态为 。BatchStatusBatchStatus.STARTEDBatchStatus.FAILEDBatchStatus.COMPLETEDspring-doc.cn

startTime (开始时间)spring-doc.cn

A 表示开始执行时的当前系统时间。 如果步骤尚未开始,则此字段为空。java.util.Datespring-doc.cn

结束时间spring-doc.cn

A 表示执行完成时的当前系统时间, 无论它是否成功。如果步骤尚未 退出。java.util.Datespring-doc.cn

exitStatusspring-doc.cn

指示执行结果的 。这是最重要的,因为 它包含返回给调用方的退出代码。有关更多详细信息,请参阅第 5 章。 如果作业尚未退出,则此字段为空。ExitStatusspring-doc.cn

executionContextspring-doc.cn

包含需要在 执行。spring-doc.cn

读取计数spring-doc.cn

已成功读取的项目数。spring-doc.cn

writeCountspring-doc.cn

已成功写入的项目数。spring-doc.cn

提交计数spring-doc.cn

已为此执行提交的事务数。spring-doc.cn

回滚计数spring-doc.cn

由 控制的业务事务已滚动的次数 返回。Stepspring-doc.cn

readSkipCountspring-doc.cn

失败的次数,导致跳过项目。readspring-doc.cn

processSkipCountspring-doc.cn

失败的次数,导致跳过项目。processspring-doc.cn

filterCount 过滤器计数spring-doc.cn

已被 “筛选”的项目数。ItemProcessorspring-doc.cn

writeSkipCountspring-doc.cn

失败的次数,导致跳过项目。writespring-doc.cn

ExecutionContext

An 表示持久化的键/值对的集合,并且 由框架控制,以便允许开发人员在某个位置存储持久化 state 的 state 的 API 值。对于那些 熟悉 Quartz,它与 JobDataMap 非常相似。最好的使用示例是 便于重启。以平面文件输入为例,同时处理单个 行,框架会定期在 Commit Points.行为 so 允许 存储其状态,以防在运行期间发生致命错误 或者即使停电。所需要做的就是输入当前的行数 读入上下文,如以下示例所示,框架将执行 休息:ExecutionContextStepExecutionJobExecutionExecutionContextItemReaderspring-doc.cn

executionContext.putLong(getKey(LINES_READ_COUNT), reader.getPosition());

以 Stereotypes 部分中的 EndOfDay 示例为例,假设有 是将文件加载到数据库中的一个步骤 'loadData'。在第一次运行失败后, 元数据表将类似于以下示例:Jobspring-doc.cn

表 9.BATCH_JOB_INSTANCE

JOB_INST_IDspring-doc.cn

JOB_NAMEspring-doc.cn

1spring-doc.cn

结束工作spring-doc.cn

表 10.BATCH_JOB_EXECUTION_PARAMS

JOB_INST_IDspring-doc.cn

TYPE_CDspring-doc.cn

KEY_NAMEspring-doc.cn

DATE_VALspring-doc.cn

1spring-doc.cn

日期spring-doc.cn

附表。日期spring-doc.cn

2017-01-01spring-doc.cn

表 11.BATCH_JOB_EXECUTION

JOB_EXEC_IDspring-doc.cn

JOB_INST_IDspring-doc.cn

START_TIMEspring-doc.cn

END_TIMEspring-doc.cn

地位spring-doc.cn

1spring-doc.cn

1spring-doc.cn

2017-01-01 21:00spring-doc.cn

2017-01-01 21:30spring-doc.cn

失败spring-doc.cn

表 12.BATCH_STEP_EXECUTION

STEP_EXEC_IDspring-doc.cn

JOB_EXEC_IDspring-doc.cn

STEP_NAMEspring-doc.cn

START_TIMEspring-doc.cn

END_TIMEspring-doc.cn

地位spring-doc.cn

1spring-doc.cn

1spring-doc.cn

loadData (加载数据)spring-doc.cn

2017-01-01 21:00spring-doc.cn

2017-01-01 21:30spring-doc.cn

失败spring-doc.cn

表 13.BATCH_STEP_EXECUTION_CONTEXT

STEP_EXEC_IDspring-doc.cn

SHORT_CONTEXTspring-doc.cn

1spring-doc.cn

{件数=40321}spring-doc.cn

在前面的例子中,运行了 30 分钟并处理了 40,321 个“块”,其中 将表示文件中的行。此值在每次 commit 的 .在提交之前收到通知需要各种 implementations (或 an )之一,这些 implementations (或 an )将更详细地讨论 在本指南的后面部分。与前面的示例一样,假定 is 第二天重新启动。重新启动时,来自 的 最后一次运行将从数据库中重构。当 被打开时,它可以 检查它在上下文中是否有任何 stored 状态,并从那里初始化自身, 如以下示例所示:StepExecutionContextStepListenerItemStreamJobExecutionContextItemReaderspring-doc.cn

if (executionContext.containsKey(getKey(LINES_READ_COUNT))) {
    log.debug("Initializing for restart. Restart data is: " + executionContext);

    long lineCount = executionContext.getLong(getKey(LINES_READ_COUNT));

    LineReader reader = getReader();

    Object record = "";
    while (reader.getPosition() < lineCount && record != null) {
        record = readLine();
    }
}

在这种情况下,在上述代码运行后,当前行为 40,322,允许 从中断的地方重新开始。也可用于 需要保留的有关运行本身的统计信息。例如,如果平面文件 包含跨多行存在的处理订单,则可能需要 store 已处理的订单数量(这与 行读取),以便可以在末尾发送一封包含总数 正文中处理的订单数。框架为开发人员处理将此存储在 order 以正确地将其范围限定为单个 .这可能非常困难 知道是否应该使用 existing例如,使用 'EndOfDay' 示例中,当 01-01 运行第二次再次开始时, 框架认识到它是相同的,并且基于个体, 将 the 从数据库中拉出,并将其 (作为 的一部分 ) 交给 itself.相反,对于 01-02 运行,框架 识别出它是一个不同的实例,因此必须将空上下文交给 .框架为 developer,以确保在正确的时间向他们提供状态。这也很重要 以注意在任何给定时间都只存在一个 per。 的客户端应该小心,因为这会创建一个共享的 键空间。因此,在输入值时应小心,以确保没有数据 覆盖。但是,在上下文中绝对不存储任何数据,因此没有 对框架产生不利影响的方式。StepExecutionContextStepJobInstanceExecutionContextJobInstanceStepExecutionContextStepExecutionStepStepExecutionContextStepExecutionExecutionContextStepspring-doc.cn

同样重要的是要注意,至少有一个 per 和 one for each .例如,请考虑以下 代码片段:ExecutionContextJobExecutionStepExecutionspring-doc.cn

ExecutionContext ecStep = stepExecution.getExecutionContext();
ExecutionContext ecJob = jobExecution.getExecutionContext();
//ecStep does not equal ecJob

如注释中所述,不等于 。他们是两个不同的。范围限定为 的 URL 将保存在 中的每个提交点,而范围限定为 Job 的 URL 将在每次执行之间保存。ecStepecJobExecutionContextsStepStepStepspring-doc.cn

在 中,所有非瞬态条目都必须为 。 执行上下文的正确序列化为步骤和作业的重启功能奠定了基础。 如果您使用的键或值本身不可序列化,则需要 采用定制的序列化方法。无法序列化执行上下文 可能会危及状态持久化过程,使失败的作业无法正确恢复。ExecutionContextSerializable

JobRepository 仓库

JobRepository是上面提到的所有 Stereotype 的持久化机制。 它为 、 和 implementations提供 CRUD 操作。首次启动时,将从存储库获取 a,并且在 执行过程和实现是持久的 通过将它们传递到存储库。JobLauncherJobStepJobJobExecutionStepExecutionJobExecutionspring-doc.cn

Spring Batch XML 名称空间为配置实例提供支持 替换为标签,如以下示例所示:JobRepository<job-repository>spring-doc.cn

<job-repository id="jobRepository"/>

使用 Java 配置时,注解提供了一个 作为自动配置的开箱即用组件之一。@EnableBatchProcessingJobRepositoryspring-doc.cn

作业Starters

JobLauncher表示用于启动具有给定集 的 A 的简单接口,如以下示例所示:JobJobParametersspring-doc.cn

public interface JobLauncher {

public JobExecution run(Job job, JobParameters jobParameters)
            throws JobExecutionAlreadyRunningException, JobRestartException,
                   JobInstanceAlreadyCompleteException, JobParametersInvalidException;
}

预计实现会从 获取 valid 并执行 .JobExecutionJobRepositoryJobspring-doc.cn

项目读取者

ItemReader是一个抽象,表示 , 1 的输入检索 item 的 intent 值。当 用尽了它所能提供的物品时,它 通过返回 .有关界面及其的更多详细信息 可以在 Readers And Writers 中找到各种实现。StepItemReadernullItemReaderspring-doc.cn

项目写入器

ItemWriter是一个抽象,表示 、 一个 batch 或 chunk 的输出 的项目数。通常,an 不知道它应该输入的内容 receive next,并且只知道在其当前调用中传递的 Item。更多 有关接口及其各种实现的详细信息,请参阅 Readers And WritersStepItemWriterItemWriterspring-doc.cn

Item Processor

ItemProcessor是表示项的业务处理的抽象。 当 读取一个项目,写入它们时,它提供了一个访问点来转换或应用其他业务处理。 如果在处理项时确定该项无效,则返回表示不应写出该项。有关该接口的更多详细信息,请参阅 Readers And WritersItemReaderItemWriterItemProcessornullItemProcessorspring-doc.cn

Batch 命名空间

前面列出的许多域概念都需要在 Spring 中进行配置。虽然上述接口的实现可以是 在标准 bean 定义中使用,为了方便 配置,如以下示例所示:ApplicationContextspring-doc.cn

<beans:beans xmlns="http://www.springframework.org/schema/batch"
xmlns:beans="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="
   http://www.springframework.org/schema/beans
   https://www.springframework.org/schema/beans/spring-beans.xsd
   http://www.springframework.org/schema/batch
   https://www.springframework.org/schema/batch/spring-batch.xsd">

<job id="ioSampleJob">
    <step id="step1">
        <tasklet>
            <chunk reader="itemReader" writer="itemWriter" commit-interval="2"/>
        </tasklet>
    </step>
</job>

</beans:beans>

只要已声明批处理命名空间,就可以使用其任何元素。更多 有关配置 Job 的信息,请参阅 配置 和 Running a Job (运行作业)。有关配置 的更多信息,请参阅 配置 步骤.Stepspring-doc.cn