Spring Batch 6 的新特性
本节重点介绍 Spring Batch 6.0 的主要变更。完整变更列表请参阅发布说明。
Spring Batch 6.0 包含以下功能与改进:
依赖项升级
在此次主要版本更新中,Spring 依赖项已升级至以下版本:
-
Spring Framework 7.0
-
Spring Integration 7.0
-
Spring Data 4.0
-
Spring LDAP 4.0
-
Spring AMQP 4.0
-
Spring Kafka 4.0
-
Micrometer 1.16
批处理基础设施配置改进
用于批处理基础设施配置的新注解和类
在 v6 版本之前,@EnableBatchProcessing 注解与基于 JDBC 的基础设施绑定。现在情况已不再如此。我们引入了两个新的注解来配置底层作业仓库:@EnableJdbcJobRepository 和 @EnableMongoJobRepository。
从 v6 开始,@EnableBatchProcessing 允许您为批处理基础架构配置通用属性,而存储相关的特定属性则可以通过新的专用注解来指定。
以下是如何使用这些注解的示例:
@EnableBatchProcessing(taskExecutorRef = "batchTaskExecutor")
@EnableJdbcJobRepository(dataSourceRef = "batchDataSource", transactionManagerRef = "batchTransactionManager")
class MyJobConfiguration {
@Bean
public Job job(JobRepository jobRepository) {
return new JobBuilder("job", jobRepository)
// job flow omitted
.build();
}
}
类似地,基于 DefaultBatchConfiguration 的编程模型也进行了更新,引入了两个新的配置类来定义特定于存储的属性:JdbcDefaultBatchConfiguration 和 MongoDefaultBatchConfiguration。这些类可用于以编程方式配置每个作业仓库的特定属性以及其他批处理基础设施 Bean。
默认的无资源批量处理基础设施
DefaultBatchConfiguration 类已更新,默认提供"无资源"批处理基础设施(基于 v5.2 引入的 ResourcelessJobRepository 实现)。这意味着它不再需要内存数据库(如 H2 或 HSQLDB)来存储作业仓库,而此前这是批处理元数据存储所必需的。
此外,当不使用元数据时,这一改动将提升批处理应用程序的默认性能,因为 ResourcelessJobRepository 不需要任何数据库连接或事务。
最后,这一改动将有助于减少批处理应用程序的内存占用,因为元数据存储不再需要内存数据库。
批量基础设施配置简化
在 v6 版本之前,一个非简单的 Spring Batch 应用程序的典型配置相当复杂,需要大量 bean:JobRepository、JobLauncher、JobExplorer、JobOperator、JobRegistry、JobRegistrySmartInitializingSingleton 等等。这需要大量的配置代码,例如需要在 JobRepository 和 JobExplorer 上配置相同的执行上下文序列化器。
在此版本中,我们对批处理基础设施配置进行了多项简化:
-
JobRepository现在扩展了JobExplorer接口,因此无需再单独定义JobExplorerbean。 -
JobOperator现在扩展了JobLauncher接口,因此无需再单独定义JobLauncherbean。 -
JobRegistry现在是可选的,并且足够智能以自动注册作业,因此无需再单独定义JobRegistrySmartInitializingSingletonbean。 -
事务管理器现在是可选的,如果未提供,将使用默认的
ResourcelessTransactionManager。
这减少了典型批处理应用程序所需的bean数量,并简化了配置代码。
面向分块处理模型的新实现
这并非一项新功能,而是对面向块处理模型的新实现。该新实现最初在5.1版本中作为实验性功能引入,现已于6.0版本中作为稳定功能提供。
新的实现由 ChunkOrientedStep 类提供,它替代了 ChunkOrientedTasklet / TaskletStep 类。
以下是一个使用构建器定义 ChunkOrientedStep 的示例:
@Bean
public Step chunkOrientedStep(JobRepository jobRepository, ItemReader<Person> itemReader, ItemWriter<Person> itemWriter) {
int chunkSize = 100;
return new ChunkOrientedStepBuilder<Person, Person>("step", jobRepository, chunkSize)
.reader(itemReader)
.writer(itemWriter)
.build();
}
此外,容错特性已按如下方式进行调整:
-
重试功能现在基于 Spring Framework 7 中引入的重试功能,而非之前的 Spring Retry 库
-
跳过功能已针对新实现进行了小幅调整,现在完全基于
SkipPolicy接口
以下是使用新的 ChunkOrientedStep 实现重试和跳过功能的快速示例:
@Bean
public Step faultTolerantChunkOrientedStep(JobRepository jobRepository, ItemReader<Person> itemReader, ItemWriter<Person> itemWriter) {
// retry policy configuration
int maxRetries = 10;
var retryableExceptions = Set.of(TransientException.class);
RetryPolicy retryPolicy = RetryPolicy.builder()
.maxRetries(maxRetries)
.includes(retryableExceptions)
.build();
// skip policy configuration
int skipLimit = 50;
var skippableExceptions = Set.of(FlatFileParseException.class);
SkipPolicy skipPolicy = new LimitCheckingExceptionHierarchySkipPolicy(skippableExceptions, skipLimit);
// step configuration
int chunkSize = 100;
return new ChunkOrientedStepBuilder<Person, Person>("step", jobRepository, chunkSize)
.reader(itemReader)
.writer(itemWriter)
.faultTolerant()
.retryPolicy(retryPolicy)
.skipPolicy(skipPolicy)
.build();
}
请参考 迁移指南 以获取有关如何从先前实现迁移到新实现的更多详细信息。
新的并发模型
在此版本之前,基于"并行迭代"概念的并发模型需要在不同层级进行大量状态同步,并且存在与节流和背压相关的若干限制,这导致了令人困惑的事务语义和较差的性能。
本次发布重新审视了该模型,并引入了一种基于生产者-消费者模式的简化并发处理新方案。现在,面向并发的分块处理步骤会在生产者线程与消费者线程之间使用一个有界内部队列。数据项一旦准备就绪即可被放入队列,而消费者线程则会在可处理时立即从队列中取出数据项。当一个数据块准备就绪等待写入时,生产者线程会暂停,直到该数据块完成写入后,再恢复生产数据项。
这个新模型更加高效,更易于理解,并为并发执行提供了更好的性能。
新的命令行操作符
Spring Batch 从版本 1 开始就提供了 CommandLineJobRunner。虽然这个运行器多年来很好地完成了它的任务,但在可扩展性和定制性方面开始显现出一些局限性。许多问题,如静态初始化、处理选项和参数的非标准方式、缺乏可扩展性等,都已被报告。
此外,这些问题还导致无法在Spring Boot中复用该运行器,从而造成两个项目中的代码重复以及行为差异(例如作业参数增量器的行为差异),这给许多用户带来了困惑。
本次发布引入了 CommandLineJobRunner 的现代版本,名为 CommandLineJobOperator,它允许您从命令行操作批处理作业(启动、停止、重启等),并且该版本可定制、可扩展,并已更新以适应 Spring Batch 6 中引入的新变化。
恢复失败作业执行的能力
在此版本之前,如果作业执行意外失败,只能通过手动更新数据库来恢复。这种方式容易出错,且在不同作业存储库之间不一致(因为JDBC数据库需要执行一些SQL语句,而NoSQL存储则需要一些自定义语句)。
本次发布在 JobOperator 接口中引入了一个名为 recover 的新方法,该方法允许您在所有作业存储库中一致地恢复失败的作业执行。
停止各类步骤的能力
自 v5.2 起,仅能通过 JobOperator#stop 从外部停止 Tasklet 步骤。如果自定义的 Step 实现希望处理外部停止信号,目前还无法实现。
本次发布新增了一个名为 StoppableStep 的新接口,该接口扩展了 Step,任何能够处理停止信号的步骤都可以实现此接口。
优雅关闭支持
Spring Batch 6.0 引入了对批处理作业优雅关闭的支持。此功能允许您以受控的方式停止正在运行的作业执行,确保将中断信号正确发送给正在运行的步骤。
当发起优雅关闭时,作业执行将停止当前活跃的步骤,并以支持可重启的一致状态更新作业仓库。一旦正在运行的步骤完成,作业执行将被标记为已停止,并执行所有必要的清理操作。
使用 Java Flight Recorder (JFR) 进行可观测性
除了现有的 Micrometer 指标外,Spring Batch 6.0 引入了对 Java Flight Recorder (JFR) 的支持,以提供增强的可观测性能力。
JFR(Java Flight Recorder)是内置于Java虚拟机(JVM)中的一个强大的性能分析和事件收集框架。它允许您以极低的性能开销捕获应用程序运行时行为的详细信息。
本次发布引入了多个JFR事件,用于监控批处理作业执行的关键方面,包括作业和步骤执行、项目读取与写入,以及事务边界。
使用 JSpecify 进行空安全注解
Spring Batch 6.0 的 API 现已采用 JSpecify 注解进行标注,以提供更好的空安全保证并提升代码质量。
本地分块支持
与远程分块类似,本地分块是一项新功能,允许您在同一JVM内使用多线程并行处理数据块。当您需要处理大量数据并希望充分利用多核处理器时,这项功能尤其有用。通过本地分块,您可以配置面向数据块的步骤以使用多线程并发处理数据块。每个线程将独立读取、处理和写入其自身的数据块,而步骤将管理整体执行并提交结果。
使用 Spring Integration 消息通道的 SEDA 风格
在Spring Batch 5.2中,我们引入了使用本地线程配合 BlockingQueueItemReader 和 BlockingQueueItemWriter 组件实现SEDA(分阶段事件驱动架构)风格处理的概念。基于此基础,Spring Batch 6.0引入了利用Spring Integration消息通道进行大规模SEDA风格处理的支持。这使您能够解耦批处理作业的不同阶段,并使用消息通道异步处理它们。通过利用Spring Integration,您可以轻松配置和管理消息通道,并利用消息转换、过滤和路由等功能。
Jackson 3 支持
Spring Batch 6.0 已升级以支持 Jackson 3.x 进行 JSON 处理。此次升级确保了与 Jackson 库最新功能和改进的兼容性,同时提供了更好的性能和安全性。Spring Batch 中所有与 JSON 相关的组件,例如 JsonItemReader、JsonFileItemWriter 以及 JacksonExecutionContextStringSerializer,均已更新为默认使用 Jackson 3.x。
对 Jackson 2.x 的支持已被弃用,并将在未来的版本中移除。如果您目前在 Spring Batch 应用程序中使用 Jackson 2.x,建议升级到 Jackson 3.x 以利用最新的功能和改进。
远程步骤支持
本次发布引入了对远程步骤执行的支持,允许您在远程机器或集群上执行批处理作业的步骤。此功能特别适用于大规模批处理场景,您希望将工作负载分布到多个节点以提高性能和可扩展性。远程步骤执行通过使用 Spring Integration 消息通道实现,该通道支持本地作业执行环境与远程步骤执行器之间的通信。
Lambda 风格配置
本次发布引入了使用上下文Lambda表达式来配置批处理构件。这种新的配置风格为定义项目读取器和写入器提供了一种更简洁、更易读的方式。
例如,与其使用传统的构建器模式,如下所示:
var reader = new FlatFileItemReaderBuilder()
.resource(...)
.delimited()
.delimiter(",")
.quoteCharacter('"')
...
.build();
现在你可以使用 lambda 表达式来配置分隔符选项,如下所示:
var reader = new FlatFileItemReaderBuilder()
.resource(...)
.delimited (config -> config.delimiter(',').quoteCharcter( '"' ))
...
.build();
弃用与清理
与任何主要版本一样,Spring Batch 6.0 中已弃用或移除了一些功能。以下变化值得注意:
-
所有先前版本中已弃用的 API 和功能均已移除
-
通过
@EnableBatchProcessing(modular = true)进行的模块化配置已被弃用 -
为了简化核心 API 并缩小其范围,此版本中已弃用多个 API
-
弃用
spring-batch-test模块中对 JUnit 4 的支持 -
弃用对 Jackson 2 的支持
-
弃用通过
batch:…命名空间进行的 XML 配置
更多详细信息,请参阅 迁移指南。