Spring Batch 5.2 中的新特性
本节重点介绍了 Spring Batch 5.2 中的主要变更。要查看完整的变更列表,请参阅 发布说明。
Spring Batch 5.2 包含以下特性:
依赖项升级
在本次发布中,Spring 依赖已升级到以下版本:
-
Spring Framework 6.2.0
-
Spring Integration 6.4.0
-
Spring Data 3.4.0
-
Spring Retry 2.0.10
-
Spring LDAP 3.2.8
-
Spring AMQP 3.2.0
-
Spring Kafka 3.3.0
-
Micrometer 1.14.1
MongoDB 作业存储库支持
此版本引入了第一个由 MongoDB 支持的 NoSQL 作业存储库实现。与关系型作业存储库实现类似,Spring Batch 提供了一个脚本,用于在 MongoDB 中创建必要的集合,以便保存和检索批处理元数据。
此实现需要 MongoDB 4 或更高版本,并基于 Spring Data MongoDB。为了使用该作业存储库,您需要做的就是定义一个 MongoTemplate
和一个 MongoTransactionManager
,它们是新添加的 MongoJobRepositoryFactoryBean
所需的:
@Bean
public JobRepository jobRepository(MongoTemplate mongoTemplate, MongoTransactionManager transactionManager) throws Exception {
MongoJobRepositoryFactoryBean jobRepositoryFactoryBean = new MongoJobRepositoryFactoryBean();
jobRepositoryFactoryBean.setMongoOperations(mongoTemplate);
jobRepositoryFactoryBean.setTransactionManager(transactionManager);
jobRepositoryFactoryBean.afterPropertiesSet();
return jobRepositoryFactoryBean.getObject();
}
一旦定义了 MongoDB 作业存储库,就可以像普通的作业存储库一样,在任何作业或步骤中注入它。你可以在 MongoDBJobRepositoryIntegrationTests 中找到一个完整的示例。
新的无资源作业存储库
在 v5 中,基于内存 Map 的作业存储库实现因多种原因被移除。Spring Batch 中唯一保留的作业存储库实现是 JDBC 实现,它需要一个数据源。虽然这与 H2 或 HSQLDB 等内存数据库配合使用效果很好,但对许多我们社区的用户来说,需要数据源是一个很强的限制条件,因为他们之前使用基于 Map 的存储库时没有任何额外依赖。
在本次发布中,我们引入了一种 JobRepository
实现,它不会以任何形式使用或存储批处理元数据(甚至不在内存中)。这是一种“无操作 (NoOp)”实现,它会丢弃批处理元数据,并且不与任何资源进行交互(因此命名为“无资源作业存储库”,该名称源自“无资源事务管理器”)。
此实现适用于不需要可重启性且执行上下文完全不参与的使用场景(例如,通过执行上下文在步骤之间共享数据,或者在分区步骤中分区元数据通过执行上下文在管理器和工作线程之间共享等)。
此实现适用于在自己的 JVM 中执行的一次性任务。它可以与事务性步骤(例如,使用 DataSourceTransactionManager
配置)以及非事务性步骤(使用 ResourcelessTransactionManager
配置)一起工作。该实现不是线程安全的,不应在任何并发环境中使用。
Composite Item Reader 实现
类似于 CompositeItemProcessor
和 CompositeItemWriter
,我们引入了一种新的 CompositeItemReader
实现,它旨在从具有相同格式的多个来源中依次读取数据。当数据分布在不同的资源中,并且编写自定义读取器不是一个选项时,这非常有用。
CompositeItemReader
通过按顺序将读取操作委托给常规项读取器来工作,类似于其他复合 artifact。以下是一个快速示例,展示了一个复合读取器如何从平面文件然后从数据库表中读取人员数据:
@Bean
public FlatFileItemReader<Person> itemReader1() {
return new FlatFileItemReaderBuilder<Person>()
.name("personFileItemReader")
.resource(new FileSystemResource("persons.csv"))
.delimited()
.names("id", "name")
.targetType(Person.class)
.build();
}
@Bean
public JdbcCursorItemReader<Person> itemReader2() {
String sql = "select * from persons";
return new JdbcCursorItemReaderBuilder<Person>()
.name("personTableItemReader")
.dataSource(dataSource())
.sql(sql)
.beanRowMapper(Person.class)
.build();
}
@Bean
public CompositeItemReader<Person> itemReader() {
return new CompositeItemReader<>(Arrays.asList(itemReader1(), itemReader2()));
}
Java.util.function API 的新适配器
类似于将 java.util.function.Function
适配为项处理器的 FucntionItemProcessor
,此版本引入了几个新的适配器,用于其他 java.util.function
接口,例如 Supplier
、Consumer
和 Predicate
。
新添加的适配器有:SupplierItemReader
、ConsumerItemWriter
和 PredicateFilteringItemProcessor
。有关这些新适配器的更多详细信息,请参阅 org.springframework.batch.item.function 包。
使用阻塞队列的并发步骤与项读取器和写入器
分阶段事件驱动架构 (SEDA)是一种强大的架构风格,用于通过队列连接的多个阶段处理数据。这种风格可以直接应用于数据管道,并且由于 Spring Batch 具有将作业设计为步骤序列的能力,因此很容易实现。
这里唯一缺少的部分是如何从中间队列读取数据和向中间队列写入数据。此版本引入了一个项读取器(item reader)和一个项写入器(item writer),用于从 BlockingQueue
读取数据并将数据写入其中。通过这两个新类,可以设计一个第一步将数据准备到队列中,以及一个第二步从同一个队列中消费数据。这样,两个步骤可以并发运行,以非阻塞、事件驱动的方式高效处理数据。
JPA 项读取器中的查询提示支持
在 5.1 版本之前,JPA 游标和分页项读取器不支持查询提示(例如获取大小、超时等)。用户需要提供自定义查询提供程序来指定自定义提示。
在此次发布中,JPA 读取器及其各自的构建器已更新,现在可以在定义要使用的 JPA 查询时接受查询提示。
JDBC 项目读取器中的数据类支持
此版本在 JDBC 游标和分页项读取器的构建器中引入了一种新方法,允许用户在项的类型为数据类(Java 记录或 Kotlin 数据类)时指定一个 DataClassRowMapper
。
新方法 dataRowMapper(TargetType.class)
与 beanRowMapper(TargetType.class)
类似,旨在使普通类(Java beans)和数据类(Java records)之间的行映射器配置保持一致。
可配置的行分隔符在 RecursiveCollectionLineAggregator 中
到目前为止,RecursiveCollectionLineAggregator
中的行分隔符属性被设置为系统的行分隔符值。虽然可以通过系统属性更改该值,但这种配置方式与其他批处理工件的属性不一致。
此版本在 RecursiveCollectionLineAggregator
中引入了一个新的设置器,允许用户配置自定义的行分隔符值,而无需使用系统属性。
作业注册改进
在版本 5.1 中,批量基础设施 Bean 的默认配置已更新,通过在应用程序上下文中定义一个 JobRegistryBeanPostProcessor
Bean,自动填充作业注册表。在 Spring Framework 最近的一次更改中,BeanPostProcessorChecker
的日志级别发生了变化,这导致在典型的 Spring Batch 应用程序中记录了与 JobRegistryBeanPostProcessor
相关的多个警告。这些警告是由于 JobRegistryBeanPostProcessor
对 JobRegistry
Bean 有依赖关系,这种依赖不被推荐,并且可能会引发 Bean 生命周期问题。
这些问题在本次发布中通过更改填充 JobRegistry
的机制得以解决,即从使用 BeanPostProcessor
改为使用 SmartInitializingSingleton
。JobRegistryBeanPostProcessor
现已弃用,取而代之的是新添加的 JobRegistrySmartInitializingSingleton
。