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 faulTolerantChunkOrientedStep(JobRepository jobRepository, ItemReader<Person> itemReader, ItemWriter<Person> itemWriter) {
// retry policy configuration
int maxRetries = 10;
var retrybaleExceptions = Set.of(TransientException.class);
RetryPolicy retryPolicy = RetryPolicy.builder()
.maxRetries(maxRetries)
.includes(retrybaleExceptions)
.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 虚拟机 (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 配置
有关更多详细信息,请参阅迁移指南。