天天看点

SpringBatch系列文章-领域模型语言

文章目录

    • 批处理的域语言
    • Job作业
      • JobInstance
      • JobParameters作业参数
      • JobExecution工作执行
    • Step步骤
      • StepExecution
    • JobRepository
    • JobLauncher作业启动器
      • ItemReader单元读
      • ItemWriter单元写
      • ItemProcessor单元处理

原文地址: https://docs.spring.io/spring-batch/docs/4.2.x/reference/html/domain.html#domainLanguageOfBatch,本翻译使用网页翻译功能,只是为了方便看。

原网站支持XML格式和JAVA格式,主要体现在代码那块,这里主要是Java版本。

批处理的域语言

对于任何经验丰富的批处理设计师而言,Spring Batch中使用的批处理的总体概念应该是熟悉且舒适的。有“工作”和“步骤”,以及开发人员提供的处理单元,称为ItemReader和ItemWriter。但是,由于存在Spring模式,操作,模板,回调和惯用语,因此有以下机会:

  • 遵守关注点明显分开的情况得到了显着改善。
  • 清楚地描述了作为接口提供的体系结构层和服务。
  • 简单和默认的实现,可以快速采用和开箱即用。
  • 显着增强的可扩展性。

下图是已经使用了数十年的批处理参考体系结构的简化版本。它概述了组成批处理领域语言的组件。该体系结构框架是一个蓝图,已经在最后几代平台(COBOL / Mainframe,C / Unix,现在是Java /任何地方)上数十年的实现中得到了证明。JCL和COBOL开发人员可能会像C,C#和Java开发人员一样熟悉这些概念。Spring Batch提供了层,组件和技术服务的物理实现,这些层,组件和技术服务通常在健壮,可维护的系统中找到,这些系统用于解决从简单到复杂的批处理应用程序的创建,其基础结构和扩展可以满足非常复杂的处理需求。

SpringBatch系列文章-领域模型语言

图1.批处理原型

上图突出显示了构成Spring Batch领域语言的关键概念。作业有一个到多个步骤,每个步骤都只有一个ItemReader,一个ItemProcessor和一个步骤ItemWriter。需要启动一个作业(带有 JobLauncher),并且需要存储有关当前正在运行的进程的元数据(位于中 JobRepository)。

Job作业

本节描述与批处理作业的概念有关的构造型。

A Job是封装整个批处理过程的实体

。与其他Spring项目一样,a Job与XML配置文件或基于Java的配置连接在一起。该配置可以被称为“作业配置”。但是,

Job这只是整个层次结构的顶部

,如下图所示:

SpringBatch系列文章-领域模型语言

图2.作业层次结构

在Spring Batch中,

a Job只是Step实例的容器

。它组合了逻辑上属于流程的多个步骤,并允许配置所有步骤全局的属性,例如可重新启动性。作业配置包含:

  • 作业的简单名称。
  • Step实例的定义和顺序。
  • 作业是否可重新启动。

Spring Batch以SimpleJob类的形式提供Job接口的默认简单实现,该实现在之上创建了一些标准功能Job。使用基于Java的配置时,可使用一组构建器来实例化a Job,如以下示例所示:

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

XML格式配置:

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

JobInstance

A JobInstance是指逻辑作业运行的概念。考虑一个应该在一天结束时运行一次的批处理作业,例如Job上图中的“ EndOfDay” 。有一个“ EndOfDay”作业,但是Job必须单独跟踪每个运行。对于这项工作,JobInstance每天只有一个逻辑。例如,有1月1日运行,1月2日运行,依此类推。如果1月1日运行第一次失败并在第二天再次运行,则仍是1月1日运行。(通常,这也与它正在处理的数据相对应,这意味着1月1日运行处理1月1日的数据)。因此,每个JobInstance执行可以有多个执行(JobExecution本章稍后将详细讨论),并且

只有一个JobInstance可以在给定时间运行Job与特定内容和标识相对应的内容JobParameters

a的定义JobInstance绝对与要加载的数据无关。完全取决于ItemReader实现来确定如何加载数据。例如,在EndOfDay方案中,数据上可能有一列指示该数据所属的“生效日期”或“计划日期”。因此,1月1日的运行将仅加载第1次的数据,而1月2日的运行将仅使用第2次的数据。由于此确定可能是一项业务决策,因此由 ItemReader决定。但是,使用同一个参数可JobInstance确定是否使用ExecutionContext先前执行中的“状态”(即本章稍后讨论的)。使用新的JobInstance 表示“从头开始”,使用现有实例通常意味着“从上次中断的地方开始”。

JobParameters作业参数

在讨论JobInstance了它与Job的不同之处之后,自然要问的问题是:“一个人JobInstance与另一个人有什么区别?” 答案是: JobParameters。一个JobParameters对象拥有一组用于启动批处理作业的参数。它们可以在运行期间用于标识甚至用作参考数据,如下图所示:

工作参数

SpringBatch系列文章-领域模型语言

图3.作业参数

在前面的示例中,有两个实例,一个实例是1月1日,另一个实例是1月2日,实际上只有一个实例,Job但是它有两个JobParameter对象:一个实例是用job参数01-01-2017启动的,另一个实例是该参数以01-02-2017开头。因此,合同可以定义为:JobInstance= Job +标识JobParameters。这使开发人员可以有效地控制a JobInstance的定义方式,因为他们可以控制传入的参数。

并非所有作业参数都需要有助于识别 JobInstance。默认情况下,它们会这样做。但是,该框架还允许提交Job带有对a的身份无贡献的参数的a JobInstance。

JobExecution工作执行

A JobExecution是指一次尝试运行Job的技术概念。执行可能以失败或成功结束,但是JobInstance与给定执行相对应的执行除非成功完成,否则不视为完成。以Job前面描述的EndOfDay 为例,考虑JobInstance01-01-2017的首次运行失败。如果使用与第一次运行(01-01-2017)相同的标识作业参数再次运行,JobExecution则会创建一个新的。但是,仍然只有一个JobInstance。

A Job定义什么是作业及其执行方式,而a JobInstance是将执行组合在一起的纯粹的组织对象,主要用于启用正确的重新启动语义。JobExecution但是,A 是运行期间实际发生情况的主要存储机制,它包含许多必须控制和保留的属性,如下表所示:

表1. JobExecution属性

属性 定义
Status 甲BatchStatus对象,指示执行的状态。在运行时,它是 BatchStatus#STARTED。如果失败,则为BatchStatus#FAILED。如果成功完成,那就是BatchStatus#COMPLETED
startTime 一个java.util.Date代表当执行开始时的当前系统时间。如果作业尚未开始,则此字段为空。
endTime 一个java.util.Date代表当执行完成后,无论它是否是成功的当前系统时间。如果作业尚未完成,则该字段为空。
exitStatus 的ExitStatus,说明运行的结果。这是最重要的,因为它包含返回给调用者的退出代码。有关更多详细信息,请参见第5章。如果作业尚未完成,则该字段为空。
createTime 甲java.util.Date表示当当前系统时间JobExecution最早持续。作业可能尚未启动(因此没有启动时间),但是它始终具有createTime,这是管理作业级别的框架所需的ExecutionContexts。
最近更新时间 java.util.Date代表上一次JobExecution持续存在的A。如果作业尚未开始,则此字段为空。
executionContext “属性包”包含两次执行之间需要保留的所有用户数据。
failureExceptions 执行Job。时遇到的异常列表。如果在失败时遇到多个异常,这些功能将非常有用Job。

这些属性很重要,因为它们可以持久保存,并且可以用来完全确定执行状态。例如,如果01-01的EndOfDay作业在9:00 PM执行并在9:30失败,则在批处理元数据表中进行以下输入:

后面设计表的直接看官网即可,有时间再慢慢整理格式。

表2. BATCH_JOB_INSTANCE

JOB_INST_ID JOB_NAME
1个 EndOfDayJob

表3. BATCH_JOB_EXECUTION_PARAMS

为了清楚和格式化,列名可能已被缩写或删除。

现在工作失败了,假设确定问题已花费了一整夜,因此“批处理窗口”现在关闭了。进一步假设该窗口在9:00 PM开始,该作业将在01-01再次开始,从停止的地方开始,并在9:30成功完成。因为现在是第二天,所以也必须运行01-02作业,此作业随后才在9:31开始,并在正常的一小时时间内在10:30完成。并不需要一个接一个JobInstance地启动,除非这两个作业有可能尝试访问相同的数据,从而导致在数据库级别锁定的问题。完全由调度程序确定何时Job应运行a。由于它们是分开的JobInstances,Spring Batch不会尝试阻止它们同时运行。(尝试JobInstance在另一个已经运行的情况下运行相同的结果 JobExecutionAlreadyRunningException会抛出该错误)。现在,JobInstance和JobParameters表中都应该有一个额外的条目,并且表中应该有两个额外的条目, JobExecution如下表所示:

表5. BATCH_JOB_INSTANCE

表6. BATCH_JOB_EXECUTION_PARAMS

表7. BATCH_JOB_EXECUTION

为了清楚和格式化,列名可能已被缩写或删除。

Step步骤

A Step是一个域对象,封装了批处理作业的一个独立的顺序阶段。因此,每个作业完全由一个或多个步骤组成。一个Step包含了所有的定义和控制实际的批量处理所需的信息。这是一个模糊的描述,因为任何给定的内容Step都由开发人员自行决定编写Job。A Step可以根据开发人员的要求简单或复杂。一个简单的方法Step可能会将文件中的数据加载到数据库中,几乎不需要代码(取决于所使用的实现)。较复杂的 Step业务规则可能包含复杂的业务规则,这些规则将在处理过程中应用。与a一样Job,a Step有一个个体StepExecution与unique相关联 JobExecution,如下图所示:

图2.1:带步骤的作业层次结构

SpringBatch系列文章-领域模型语言

图4.带有步骤的作业层次结构

StepExecution

A StepExecution代表执行的单次尝试Step。StepExecution 每次Step运行a都会创建一个新内容,类似于JobExecution。但是,如果某个步骤由于执行失败而无法执行,则不会继续执行。A StepExecution仅在其Step实际启动时创建。

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

表8. StepExecution属性

ExecutionContext执行上下文

An ExecutionContext表示键/值对的集合,这些键/值对由框架进行持久化和控制,以便允许开发人员存储一个范围为StepExecution对象或JobExecution对象的持久状态。对于熟悉Quartz的人来说,它与JobDataMap非常相似。最佳用法示例是促进重新启动。以平面文件输入为例,在处理各个行时,框架会定期保留ExecutionContext提交点**

(批注:通过对footballl例子的运行,批量提交一次记录一次,和chunk中commit-interval有关,大致是总数据量除以一次提交的数量)

**。这样做可以ItemReader在运行期间发生致命错误或断电的情况下存储其状态。所需要做的就是将当前读取的行数放入上下文中,如下面的示例所示,框架将完成其余工作:

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

以JobStereotypes部分的EndOfDay示例为例,假设有一个步骤“ loadData”将文件加载到数据库中。第一次失败运行后,元数据表将类似于以下示例:

看官网表格,这里不复制了。

在上述情况下,Step运行了30分钟并处理了40321个“件”,在这种情况下,这代表了文件中的行。此值会在框架每次提交之前更新,并且可以包含与中的条目相对应的多行 ExecutionContext。在提交之前得到通知需要各种 StepListener实现之一(或ItemStream),本指南后面将对此进行详细讨论。与前面的示例一样,假定Job于第二天重新启动。重新启动后,ExecutionContext将从数据库中重新构建上次运行的值。当ItemReader被打开时,它可以检查以查看它是否具有在上下文任何存储的状态,并从那里初始化自身,如图以下示例:

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

在这种情况下,运行上述代码后,当前行为40322,从而允许Step 再次从中断处开始。该ExecutionContext也可用于那些需要被保留的关于运行本身的统计数据。例如,如果平面文件包含跨多行存在的处理订单,则可能有必要存储已处理的订单数量(与读取的行数有很大不同),以便可以通过以下方式发送电子邮件:结束Step于正文中处理的订单总数。框架负责为开发人员存储此内容,以便将其正确地界定为个人JobInstance。很难知道是否存在ExecutionContext是否应该使用。例如,使用上面的’EndOfDay’示例,当01-01运行第二次再次开始时,框架会识别出它是相同的JobInstance并且是单独的Step,将其ExecutionContext拉出数据库,并将其移交给数据库(作为自身的一部分 StepExecution)Step。相反,对于01-02运行,框架识别出它是一个不同的实例,因此必须将空上下文传递给 Step。框架为开发人员做出了许多类型的确定,以确保在正确的时间将状态提供给开发人员。同样重要的是要注意,在任何给定时间,ExecutionContext每个人都只存在一个StepExecution。客户ExecutionContext应该小心,因为这会创建一个共享的键空间。因此,在输入值时应注意确保没有数据被覆盖。但是,Step存储绝对不会在上下文中存储任何数据,因此没有办法对框架产生不利影响。

同样重要的是要注意,至少有一个ExecutionContext每 JobExecution一个用于每一个StepExecution。例如,考虑以下代码片段:

ExecutionContext ecStep = stepExecution.getExecutionContext();

ExecutionContext ecJob = jobExecution.getExecutionContext();

//ecStep does not equal ecJob

如评论中所述,ecStep不等于ecJob。他们是两个不同的人 ExecutionContexts。范围为的Step一个保存在中的每个提交点 Step,而范围为的一个保存在每次Step执行之间。

JobRepository

JobRepository是上述所有构造型的持久性机制。它提供了CRUD操作JobLauncher,Job以及Step实现。当 Job第一次启动,一个JobExecution被从库中获得,并且,执行的过程中,StepExecution和JobExecution实施方式是通过将它们传递到存储库持续。

使用Java配置时,@EnableBatchProcessing注释提供 JobRepository作为开箱即用自动配置的组件之一。

批处理名称空间为JobRepository使用标签配置实例 提供了支持,如以下示例所示:

JobLauncher作业启动器

JobLauncher表示一个用于启动Job带有给定集合的 的简单界面JobParameters,如以下示例所示:

public interface JobLauncher {

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

预计实现获得有效JobExecution距离 JobRepository和执行Job。

ItemReader单元读

ItemReader是一种抽象,表示一次检索一项的输入Step。当ItemReader用尽了它可以提供的物品时,它通过返回来表明这一点null。有关ItemReader接口及其各种实现的更多详细信息,请参见 读者和作家。

ItemWriter单元写

ItemWriter是一个抽象,一次代表一个Step,一批或大块项目的输出。通常,一个ItemWriter不知道下一步应该接收的输入,并且只知道当前调用中传递的项目。有关ItemWriter接口及其各种实现的更多详细信息,请参见 读者和作家。

ItemProcessor单元处理

ItemProcessor是表示项目的业务处理的抽象。在ItemReader读取一项并将其ItemWriter写入的同时,它们 ItemProcessor提供了一个访问点来转换或应用其他业务处理。如果在处理项目时确定该项目无效,则返回 null指示不应写出该项目。有关该ItemProcessor接口的更多详细信息,请 参见 读者和作家。

版本4.2.4.RELEASE 最后更新时间2020-06-11 07:52:24 UTC

继续阅读