Spring Batch 6.1.0-RC1 and 6.0.6 available now!
TL;DR · AI 摘要
Spring Batch 6.1.0-RC1发布,包含依赖升级、@JobParameter注解和新组件,提升开发效率与类型安全性。
核心要点
- Spring Framework升级至7.1.0-RC1,增强生态兼容性
- @JobParameter注解简化参数注入,替代复杂SpEL表达式
- PageableItemReader通过类型安全替代RepositoryItemReader
结构提纲
按章节快速跳转。
- §版本发布
宣布Spring Batch 6.1.0-RC1和6.0.6正式发布,包含多项改进。
- ·依赖升级
升级Spring Framework至7.1.0-RC1及多个子项目至RC1版本。
提供更简洁的参数注入方式,替代原有SpEL表达式。
- ·新组件
引入PageableItemReader等组件,提升类型安全性与开发效率。
思维导图
用一张图看清主题之间的关系。
查看大纲文本(无障碍 / 无 JS 友好)
- Spring Batch 6.1.0-RC1更新
- 依赖升级
- Spring Framework 7.1.0-RC1
- 新特性
- @JobParameter注解
- PageableItemReader组件
金句 / Highlights
值得收藏与分享的关键句。
Spring Framework升级至7.1.0-RC1,Spring Data升级至2026.1.0-RC1
@JobParameter注解默认使用字段名作为参数名,简化配置
PageableItemReader通过编译期检查替代反射调用,减少运行时错误
我谨代表团队及所有贡献者,高兴地宣布 Spring Batch 6.1.0-RC1 和 6.0.6 现已通过 Maven Central 发布!这些版本带来了许多新功能、改进和错误修复。如需查看完整的变更列表,请查阅发布说明:6.1.0-RC1 和 6.0.6。
本文将带您了解 6.1.0-RC1 的主要变更内容:
- 依赖项升级
- 用于注入作业参数的
@JobParameter注解 - 新增
PageableItemReader JsonLineMapper与 JSON 库无关- 新增
JsonLineAggregator - 新增
RemoteChunkingManagerBuilder - 新增
DefaultChunkProcessor - JDBC DAO 迁移到
JdbcClient - 性能优化
依赖项升级
Spring 依赖项已升级至以下版本:
- Spring Framework 7.1.0-RC1
- Spring Integration 7.2.0-RC1
- Spring Data 2026.1.0-RC1
- Spring LDAP 4.2.0-RC1
- Spring AMQP 4.2.0-RC1
- Spring Kafka 4.2.0-RC1
- Micrometer 1.18.0-RC1
用于注入作业参数的 `@JobParameter` 注解
以前将作业参数注入作业或步骤作用域的 Bean 需要使用 SpEL 表达式,这种表达式仅在运行时进行求值且容易出错。新的 @JobParameter 注解提供了更简洁的替代方案,默认将作业参数名称设置为注解字段或参数的名称:
@Bean
@StepScope
public FlatFileItemReader<Foo> fooReader(@JobParameter String inputFile) {
return new FlatFileItemReaderBuilder<Foo>()
.resource(new FileSystemResource(inputFile))
// 其他属性省略
.build();
}这替代了 @Value("#{jobParameters['inputFile']}")。名称也可以显式指定,例如 @JobParameter("input.file.name")。与它替代的表达式一样,它适用于在作业或步骤作用域中定义的 Bean。当方法或构造函数参数上省略名称时,代码必须使用 -parameters 标志进行编译,这是 Spring Boot Maven 和 Gradle 插件的默认设置。更多详情请参见 issue #5563。
新增 `PageableItemReader`
PageableItemReader 是 RepositoryItemReader 的类型安全替代方案。它不通过名称反射性地调用仓库方法,而是使用从 Spring Data Pageable 到 Slice 的函数,该函数在编译时进行检查:
PageableItemReader<Customer> reader = new PageableItemReaderBuilder<Customer>()
.query(customerRepository::findAll)
.sort(Sort.by(Sort.Direction.ASC, "id"))
.pageSize(100)
.name("customerReader")
.build();排序也可以通过 Spring Data 的 类型安全属性引用 来实现,例如 Sort.by(Sort.Direction.ASC, Customer::getId),这种方式消除了基于字符串的属性名称。
`JsonLineMapper` 与 JSON 库无关
JsonLineMapper 以前只能将 JSON Lines 文件的每一行映射到 Map<String, Object>,并且只能使用 Jackson 实现。现在它已成为泛型,并委托给新的 JsonObjectUnmarshaller 来转换行,这使其独立于 JSON 库,能够将行映射到任何类型,例如领域类或记录。提供了基于 Jackson 和 Gson 的实现:
record Trade(String isin, int quantity, double price, String customer) {
}
FlatFileItemReader<Trade> reader = new FlatFileItemReaderBuilder<Trade>()
.name("tradeReader")
.resource(resource)
.lineMapper(new JsonLineMapper<>(new JacksonJsonObjectUnmarshaller<>(Trade.class)))
// 或 .lineMapper(new JsonLineMapper<>(new GsonJsonObjectUnmarshaller<>(Trade.class)))
.build();无参数构造函数和接受 JsonMapper 的构造函数已弃用,取而代之的是 JsonLineMapper(JsonObjectUnmarshaller)。这些旧构造函数将在 7.0 版本中被移除。这对使用原始 JsonLineMapper 类型并直接在其上调用 mapLine 的代码来说是一个源代码和二进制兼容性破坏性变更。仅将映射器传递给读取器的代码只需重新编译即可,无需其他更改。更多细节请参见 参考文档。
新的 `JsonLineAggregator`
JsonLineAggregator 是 JsonLineMapper 的写入端对应实现:一个 LineAggregator,它使得通过 FlatFileItemWriter 将项目写入 JSON Lines 文件成为可能。与映射器类似,它也与 JSON 库无关,因为它将项目转换委托给 JsonObjectMarshaller,因此可以使用 Jackson 或 Gson 实现:
FlatFileItemWriter<Trade> writer = new FlatFileItemWriterBuilder<Trade>()
.name("tradeWriter")
.resource(new FileSystemResource("trades.jsonl"))
.lineAggregator(new JsonLineAggregator<>(new JacksonJsonObjectMarshaller<>()))
.build();新的 `RemoteChunkingManagerBuilder`
RemoteChunkingManagerBuilder 是 RemoteChunkingWorkerBuilder 的对应实现,用于配置远程分块设置中的管理器步骤。它仅包含与远程分块相关的特定设置(通道、消息模板、最大等待超时次数和节流限制),而 chunk(int) 方法会返回一个标准的 ChunkOrientedStepBuilder 用于其他所有配置。生成的步骤是一个 ChunkOrientedStep,构建器不会暴露任何弃用的 API:
@Bean
public Step managerStep(JobRepository jobRepository, PlatformTransactionManager transactionManager) {
return new RemoteChunkingManagerBuilder("managerStep", jobRepository)
.outputChannel(requests())
.inputChannel(replies())
.chunk(100)
.reader(itemReader())
.transactionManager(transactionManager)
.build();
}RemoteChunkingManagerStepBuilder 和 RemoteChunkingManagerStepBuilderFactory 已被弃用,取而代之的是当前的构建器,计划在 7.0 版本中移除。需要注意的是,事务管理器默认使用无资源的实现,而之前的工厂类使用的是应用上下文中的事务管理器,因此如果 manager step 的项读取器需要事务资源,必须显式设置。
新的 `DefaultChunkProcessor`
由于 SimpleChunkProcessor 是 6.0 版本中遗留的基于块处理引擎的一部分,已被弃用。但此前它仍是处理步骤外块(例如远程分块工作者或 ChunkTaskExecutorItemWriter)的唯一方式。DefaultChunkProcessor 是这些场景的替代方案。它是一个最小化的 ChunkProcessor,对块中的每个项应用可选的 ItemProcessor,并通过 ItemWriter 写入结果,例如 new DefaultChunkProcessor<>(itemProcessor, itemWriter)。与 SimpleChunkProcessor 不同的是,它不支持监听器且不记录指标。RemoteChunkingWorkerBuilder 现在内部使用它。
JDBC DAO 迁移到 `JdbcClient`
作业仓库 DAO 的 JDBC 实现(JdbcJobInstanceDao、JdbcJobExecutionDao、JdbcStepExecutionDao 和 JdbcExecutionContextDao)现在使用 Spring Framework 的 JdbcClient 替代 JdbcOperations 来访问批处理元数据表。这为它们提供了命名参数和用于查询、更新和批量更新的单一流畅 API。客户端现在是必需的协作对象,因此需要通过构造函数传递:
JdbcJobInstanceDao jobInstanceDao = new JdbcJobInstanceDao(JdbcClient.create(dataSource));通过 @EnableBatchProcessing、@EnableJdbcJobRepository、JdbcDefaultBatchConfiguration、JdbcJobRepositoryFactoryBean 或 JobExplorerFactoryBean 配置作业仓库的应用程序不受影响,因为这些配置会自行构建 DAO。但对于直接实例化这些 DAO 的代码,这是一个源码和二进制兼容性破坏性变更,因为它们的无参数构造函数已被移除。因此,AbstractJdbcBatchMetadataDao#setJdbcTemplate(JdbcOperations) 和 #getJdbcTemplate() 已被弃用,取而代之的是新的构造函数和 #getJdbcClient()。更多细节请参见 issue #4804。
性能改进
此版本对作业仓库和分片步骤的多个部分进行了优化,使其运行更快且内存占用更少。以下是主要改进点。
作业启动与重启
重启作业时,以前需要读取其作业实例的完整历史记录,加载所有过去的执行及其所有步骤。因此,作业重启的频率越高,每次重启所需的 SQL 语句就越多:在 6.0.4 版本中,相同失败作业的第 12 次重启会生成 130 条语句,每次过去的执行多出 8 条。现在仅检查最后一次执行,因此重启的成本不再依赖于历史记录。此优化也适用于 6.0.6 版本。
查找作业实例的执行也更快了。JdbcJobExecutionDao#findJobExecutions 以前需要为每个执行运行 3 次额外查询(N 次执行需要 1 + 3N 次查询)。现在无论 N 的值如何,只需要 2 次查询。对于有 10 次执行的作业实例,查询次数从 31 次减少到 2 次,大约减少 15 倍。getLastJobExecution 从 4 次查询减少到 2 次,减少一半。
[分区步骤](https://spring.io/blog/2026/10/22/spring-batch-6#partitioned-steps)
MessageChannelPartitionHandler 会定期向作业库查询其工作者是否完成。每次查询时,它以前会加载每个工作者的步骤执行,并且每个工作者都会附带整个作业执行及其所有步骤执行。当分区数量较多时,内存消耗会迅速增加:在某个案例中,一个包含 837 个分区的步骤在内存中保留了 837 × 837 = 700,569 个 StepExecution 对象,负责轮询工作者的节点使用了 15 GB 内存,是执行相同工作量的另一节点的 10 倍。
现在,处理器仅通过新方法 JobRepository#countRunningStepExecutions(Collection<Long>) 统计正在运行的工作者数量,并在所有工作者完成时一次性加载作业执行。在相同案例中,对象数量从 700,569 个减少到 837 个,减少 837 倍,同时消除了轮询节点的额外内存占用:内存使用量减少约 10 倍。新方法为 default 方法,因此现有 JobRepository 实现仍可正常工作,若不支持计数功能,处理器会回退到之前的逻辑。
[JDBC 作业库](https://spring.io/blog/2026/10/22/spring-batch-6#jdbc-job-repository)
一些 JDBC DAO 的查询也被移除了。每次调用时,每个方法都能节省一次查询:
- 加载作业执行时不再运行单独的查询来查找其作业实例 ID,因为该 ID 已包含在
JOB_EXECUTION表中。 - 更新作业执行时不再先运行
SELECT COUNT(*)来检查行是否存在,因为更新操作本身会报告行缺失。 JdbcJobExecutionDao#synchronizeStatus(StepExecution)节省一次查询。- 因并发更改导致作业或步骤执行更新失败时,不再运行额外查询仅用于在错误信息中显示当前版本。
后两个优化也适用于 6.0.6 版本。
[反馈](https://spring.io/blog/2026/10/22/spring-batch-6#feedback)
感谢所有参与此次发布的贡献者!随着我们逐渐接近 6.1 GA 版本的发布,我们期待在 Github Issues、Github Discussions 和 X 上收到您的反馈。
- * *