Spring Batch 2.0 新特性概览

工程技术 | Dave Syer | 2008年10月21日 | ...

在本文中,我们概述了 Spring Batch 2.0 的主要主题,并强调了与 1.x 的变化。新版本的开发工作正在顺利进行中,上周发布了 M2 版本,并且我们获得了广泛的关注,所以现在似乎是提供一些指导的好时机。

Spring Batch 2.0 主题

新版本的四个主要主题是

  • Java 5 和 Spring 3.0
  • 非顺序执行
  • 可伸缩性
  • 配置:注解和 XML 命名空间
因此我们将分别介绍这些领域,并描述它们的含义以及这些变化对 Spring Batch 现有用户的影响。下面有关于已实现功能的更多详细信息,这些功能主要集中在第一个类别中,并在其他领域提供了一些支持性功能。

Spring Batch 2.0.0.M2 的项目物理布局没有变化(与旧版本下载相同,Java 包的基本布局也相同)。我们没有删除任何功能,但借此机会修订了一些 API,对于从 1.x 更新项目的用户来说,有一些小的变化。Spring Batch 还不够成熟,而且我们正在添加一些相当大的功能,所以我们决定进行一次主版本变更是一个很好的机会来进行一些清理。我们预计没有人会遇到升级困难,如果您是现有用户,本文将帮助您了解这些变化。

Java 5 和 Spring 3.0

正如您可能知道的,Spring 3.0 将成为 Spring 首个专门针对 Java 5 的主要版本(更详细的说明留给 Juergen 和 Arjen 来澄清)。既然 Sun 已经对 JDK 1.4 打上了 "服务生命周期结束" 的标记,这看起来是合适的,而且 Spring 3.0 中有一些我们想要利用的很棒的新功能。

类型安全

Spring Batch 2.0.0.M1 版本的大部分工作是把现有代码转换为 Java 5,尽可能地利用泛型和参数化类型。这为框架的用户提供了更愉快的编程体验,允许在编译时进行类型安全检查,最终降低了使用 Spring Batch 的项目的维护成本。例如,在ItemReader,作为 Spring Batch 中核心接口和用户扩展点之一,我们现在有一个类型安全的read方法

public interface ItemReader<S> {
    S read();
}

这里需要进一步注意的一点是,旧的(1.x)框架回调函数mark()reset()已从此接口中移除,使其对最终用户更加友好,并防止对框架何时需要什么产生误解。同样的关注点(即 mark 和 reset)现在在框架提供的Step实现中内部处理。

面向块的处理

类似的变化,以及一个稍微更彻底的变化,也发生在搭档ItemWriter接口中,框架使用它来写入数据


public interface ItemWriter<T> {
    void write(List<? extends T> items);
}

旧的框架回调函数flush()clear()也从此接口中移除,为了弥补这一点,write()方法有了新的签名。这里的重点是,我们在框架内部转向了面向块的处理范式。这在批处理框架中实际上比旧的面向项的方法更自然,因为出于性能原因,我们经常需要缓冲和刷新,而旧的接口使用户感到不便。现在您可以在write()方法内部完成所有需要的批处理。

Step Factory Bean 变更

面向块的处理方法的副作用是步骤工厂 bean 实现的改变。旧的SkipLimitStepFactoryBean已重命名为FaultTolerantStepFactoryBean,并且在大多数常见用例中仍然可以用作旧工厂 bean 的替代品。默认情况下,它创建一个步骤实现,该实现会在回滚时缓冲输入项,以便新的ItemReaderItemWriter接口能与非事务性输入源(如文件)正常工作。对于在回滚后重新提供项的输入源,客户端必须在工厂 bean 中设置一个标志(isReaderTransactional是截至 M2 版本的标志名称)-JmsItemReader是框架中唯一相关的 reader,并且使用它的项目不多,所以这不是一个大的改变。

业务处理

一个相关的新功能是,以ItemProcessor:

public interface ItemProcessor<S,T> {
    T process(S item);
}

的形式,出现了一个新成员。在 1.x 中,类型为S的输入项和类型为T的输出项之间的转换必须隐藏在其他参与者之一(通常是ItemWriter)内部。现在我们已经将这个关注点泛化,并在框架中将其置于与其兄弟姐妹ItemReaderItemWriter同等重要的地位。1.x 的用户可能会认出旧的ItemTransformer接口的痕迹,该接口现已移除。

一个更有用的 Tasklet 接口

许多人在查看 Spring Batch 1.x 时曾问过:“如果我的业务逻辑不是读取和写入怎么办?” 为了更令人满意地回答这个问题,我们修改了Tasklet接口。在 Spring Batch 1.x 中,它相当平淡——不过是一个Callable而已,但在 2.0 中,我们赋予了它更多的灵活性,并将其更多地融入了框架的主流(例如,核心的面向块的步骤实现现在被实现为一个Tasklet)。这是新的接口


public interface Tasklet {
    ExitStatus execute(StepContribution contribution, 
        AttributeAccessor attributes);
}

其思想是,tasklet 现在可以向其所在的步骤贡献更多内容,这使其成为实现业务逻辑的更加灵活的平台。StepContribution在 1.x API 中已经存在,但没有非常公开地暴露。它的作用是收集对当前StepExecution的更新,而程序员无需担心在另一个线程中发生并发修改。这也告诉我们,Tasklet将被重复调用(而不是像 1.x 框架中那样每个步骤只调用一次),因此它可以用于执行更大范围的业务处理任务。AttributeAccessor是一个块作用域的键值对集合。tasklet 可以使用它来存储在回滚时会保留的中间结果。

Job 和 Step 属性的延迟绑定

截至目前(到 M2 版本),我们还未能利用任何新的 Spring 3.0 功能,因为 Spring 3.0 还没有发布。但从下一个里程碑(M3)开始,我们将使用新的 Spring EL(表达式语言)功能来实现JobParametersExecutionContext属性到步骤组件的延迟绑定。这是一个非常需要的功能,我们在 1.x 中有一些特殊情况的临时解决方案,例如StepExecutionResourceProxy用于将文件名绑定作为作业的输入参数。Spring Batch 2.0 中提供的一个更通用的解决方案是允许这些步骤属性绑定到任意组件,通过在适当的 Spring scope 中定义它们,例如

<bean id="step1" parent="simpleStep">
  <property name="itemReader">
    <bean class="org.springframework.batch.item.file.FlatFileItemReader" scope="step">
        <property value="#{jobParameters[inputFile]}" />
        ...
    </bean>
  </property>
  ...
</bean>

该 item reader 需要绑定到一个只有在运行时才可用的文件名。为了实现这一点,我们将其声明为 scope="step" 并使用了 Spring EL 绑定模式#{...}来绑定一个作业参数。同样的模式也适用于步骤和作业级别的执行上下文属性。

StepScope在每夜构建快照中可用,但我们仍在使用 Spring 2.5.5,因此 EL 绑定尚未生效。步骤作用域的 bean 也是解决 Spring Batch 旧问题——如何保持步骤线程安全——的一个好方法。如果一个步骤依赖于像FlatFileItemReader这样的有状态组件,那么它只需要将该组件定义为 scope="step",框架就会为其创建一个延迟初始化的代理,并且在每次步骤执行时按需创建。当然,为每次作业执行创建一个新的ApplicationContext仍然没有任何问题,这是 1.x 中保持线程不跨作业冲突的最佳实践。但是现在步骤作用域为您提供了另一个选择,而且对于大多数 Spring 用户来说可能更容易理解。

非顺序执行

在 1.x 中,作业的模型始终是线性顺序的步骤,如果一个步骤失败,则作业失败。尽管许多作业仍然符合这种模式,所以它并没有消失,但在 2.0 中,我们通过引入一些新特性来解除这一限制。这些特性计划在 M3 版本中实现,因此实现细节可能会改变,但其思想是支持三个特性

  • 条件执行:根据上一个步骤的ExitStatus决定分支到不同的步骤。这包括在 FAILED 状态时进行分支的能力,这意味着步骤失败不再对作业是致命的。
  • 暂停执行并等待明确指示继续。这在例如存在强制手动干预以检查业务关键数据有效性的业务规则的情况下非常有用。
  • 多个步骤的并行执行。如果步骤是独立的,用户可以指定哪些分支可以并行执行。
截至撰写本文时,每夜构建快照包含一个ConditionalJob,支持上述第一个用例。

可伸缩性

Spring Batch 1.x 始终旨在作为单 VM、可能多线程的模型,但我们在其中内置了许多支持在多个进程中并行执行的功能。许多项目已成功实现可伸缩的解决方案,这些方案依赖于 Spring Batch 的服务质量特性来确保处理仅按正确顺序进行。在 2.0 中,我们计划更明确地公开这些功能。可伸缩性有两种方法,我们将支持这两种方法:远程分块(remote chunking)和分区(partitioning)。

远程分块

远程分块是一种在不明确了解数据结构的情况下分割步骤工作量的技术。任何输入源都可以通过在一个进程中读取(与 1.x 中正常情况一样)并以块的形式将项发送到远程工作进程来动态分割。远程进程实现监听器模式,响应请求、处理数据并发送异步回复。请求和回复的传输必须是持久的,具有保证送达和单个消费者,任何 JMS 实现都提供了这些功能。但 Spring Batch 是在 Spring One Americas

配置:注解和 XML 命名空间

使用注解实现批处理逻辑的想法类似于 Spring @MVC。最终效果是,您无需实现并可能注册一堆接口(reader、writer、processor、listeners 等),而只需注解一个 POJO 并将其插入到步骤中。有与各种接口相对应的方法级别注解,以及与 job、step 和 chunk 级别属性相对应的参数级别注解和工厂方法(有点像@ModelParameter@RequestParameter

在 Spring @MVC 中。 Spring Batch 的 XML 命名空间使得常见事物的配置更加容易。例如,我们上面提到的ConditionalJob具有 XML 配置选项,因此一个简单的条件执行可能看起来像这样


<job>
  <step name="gamesLoad" next="playerLoad"/>
  <step name="playerLoad">
    <next on="*" to="summarize"/>
    <next on="FAILED" to="compensate"/>
  </step>
  <step name="compensate"/>
  <step name="summarize"/>
</job>

name= 属性<stepXML 中的 元素是一个 bean 引用,因此Step的实现在其他地方定义(可能通过注解)。

数据库 schema 变更

在元数据 schema 中,有一些清理任务和数据模型的扩展。我们将为从 1.x 迁移到 2.0 的任何人提供更新脚本,因此它们不应该引起任何问题,并且肯定会使导航和与元数据交互更容易。对于那些刚接触 Spring Batch 的人来说,该框架的一些关键优势在于服务质量特性,例如可重启性和幂等性(仅一次且仅一次处理业务数据)。我们通过在关系数据库中的共享状态(在大多数用例中)实现这些特性,并且该数据库中的数据模型定义在 2.0 中略有改变。

主要变化与ExecutionContext的存储有关,它以前集中在一个表中,尽管上下文可以与StepExecutionJobExecution相关联。新模型会更受 DBA 的欢迎,因为它在 DDL 中使关系更加透明。我们还开始将上下文值存储在 JSON 中,以便人类用户更容易读取和跟踪(单个实体的上下文全部存储在表的一行中,而不是多行)。

我们还添加了一些关于执行和跳过项的计数和统计信息,分别统计了每个阶段读取、处理和写入的总项数。对于不将其执行拆分为读取、处理、写入的步骤(或 tasklet),这比需要的更全面,但对于大多数用例,它比仅存储总项数更合适。

总结

希望本文已经激发了您对 Spring Batch 2.0 的兴趣,并且您将有时间下载一个快照或里程碑版本并试用。我们从社区获得了如此多的良好反馈,没有您的帮助和支持,产品不会像现在这样好。如果我遗漏了您感兴趣的内容,或者提供的细节不够充分,我深表歉意,但我需要将这篇文章压缩到合理的博客篇幅。如果有人感兴趣,我可以写更多内容——请随时提问。

如果您确实想了解更多信息,在今年的 Spring One Americas 大会上,您有机会听取团队介绍 Spring Batch 2.0 和所有其他 SpringSource 的活动。Lucas Ward 将在一个会议中介绍 Spring Batch 2.0 的特性,我将更详细地展示其可伸缩性特性。您也可以查看 论坛 上的讨论,或者前往 此处 的主页。

订阅 Spring 新闻邮件

通过 Spring 新闻邮件保持联系

订阅

领先一步

VMware 提供培训和认证,助您加速前进。

了解更多

获取支持

Tanzu Spring 通过一个简单的订阅提供 OpenJDK™、Spring 和 Apache Tomcat® 的支持和二进制文件。

了解更多

近期活动

查看 Spring 社区的所有近期活动。

查看全部