Spring Batch 6 的新功能
本节重点介绍 Spring Batch 6.0 中的主要变更。如需查看完整的变更列表,请参阅 发布说明。
Spring Batch 6.0 包含以下功能和改进:
依赖项升级
在此主要版本中,Spring 依赖已升级至以下版本:
-
Spring 框架 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();
}
有关如何从以前的实现迁移到新实现的更多详细信息,请参阅 迁移指南。
新的并发模型
在此版本之前,基于“并行迭代”概念的并发模型需要在不同层级进行大量的状态同步,并且存在若干与限流和背压相关的限制,导致事务语义令人困惑且性能不佳。
此版本重新审视了该模型,并引入了一种基于生产者 - 消费者模式的新型简化并发方法。面向块(chunk-oriented)的并发步骤现在在生产者线程与消费者线程之间使用一个有界的内部队列。一旦项准备就绪即可放入队列供处理,而消费者线程则在这些项可供处理时立即从队列中取出。当一个块准备好写入时,生产者线程会暂停,直到该块完成写入,随后恢复生成新的项。
此新模型更高效、更易于理解,并为并发执行提供了更好的性能。
新的命令行操作符
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 虚拟机(JVM)中的强大性能剖析和事件收集框架。它允许您以极小的性能开销捕获应用程序运行时行为的详细信息。
此版本引入了多个 JFR 事件,用于监控批处理作业执行的关键方面,包括作业和步骤的执行、项的读取与写入,以及事务边界。
使用 JSpecify 进行空安全注解
Spring Batch 6.0 API 现已使用 JSpecify 注解进行标注,以提供更强的空安全保证并提升代码质量。
本地分块支持
与远程分块类似,本地分块是一项新功能,允许您在同一个 JVM 内使用多个线程并行处理数据项分块。当您有大量数据项需要处理并希望充分利用多核处理器时,此功能尤为有用。 通过本地分块,您可以配置一个面向分块的步骤,使用多个线程并发处理数据项分块。每个线程将独立地读取、处理和写入其自己的数据项分块,而该步骤将管理整体执行并提交结果。
采用 SEDA 风格与 Spring Integration 消息通道
在 Spring Batch 5.2 中,我们引入了使用本地线程进行 SEDA(分阶段事件驱动架构)风格处理的概念,并借助了 BlockingQueueItemReader 和 BlockingQueueItemWriter 组件。在此基础上,
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 配置
如需更多详情,请参阅 迁移指南。