领先一步
VMware 提供培训和认证,助力您快速发展。
了解更多它终于来了!Spring Batch 5.0 现已从 Maven Central 全面推出。Spring Batch 5 是两年工作的结晶,包含了 50 多位贡献者提供的数十项改进、功能和错误修复!我谨代表团队,感谢所有在这巨大版本发布中做出贡献的人!
这篇博客文章介绍了这个新一代框架的主要亮点。你可以在版本说明中找到所有变更的详细信息,并在迁移指南中找到升级说明。
Spring Batch 遵循 Spring Framework 在 Java 版本和第三方依赖方面的基线。在 Spring Batch 5 中,Spring Framework 版本已升级到 Spring Framework 6,这需要 Java 17。因此,Spring Batch 的 Java 版本要求也提高到了 Java 17。
为了继续与 Spring Batch 使用的第三方库的受支持版本集成,Spring Batch 5 将所有依赖项更新到以下版本:
此版本还标志着向以下版本的迁移:
为使用 GraalVM native-image 编译器将 Spring Batch 应用程序编译为原生可执行文件提供支持的工作始于 v4.2,并在 v4.3 中作为实验性功能发布。
在此版本中,通过提供必要的提前处理(AOT)和运行时提示,原生支持得到了显著改进,可以使用 GraalVM 原生编译 Spring Batch 应用程序。
在这篇博客文章中,我们想与你分享我们在该领域进行的一些基准测试。以下基准测试基于 Spring Native 示例项目中的 batch 示例。这些基准测试比较了使用常规 JVM 和作为原生可执行文件执行同一批处理应用程序的启动时间和总执行时间。
这里显示的值是使用以下软件和硬件配置执行示例 10 次的平均值:
这些基准测试表明,原生 Spring Batch 应用程序的启动速度快了两倍,运行时速度快了近十倍!这对云原生批处理工作负载来说绝对是一个游戏规则的改变者!
随着升级到 Micrometer 1.10,除了批处理指标外,你现在还可以获得批处理跟踪。Spring Batch 会为每个作业创建一个 Span,并为作业中的每个步骤创建一个 Span。这些跟踪元数据可以在诸如 Zipkin 之类的仪表板上收集和查看。
此外,此版本引入了新的指标:
job.launch.count
: 这是一个 Counter
,报告通过 JobLauncher
启动了多少个作业。这对于在持续运行的 JVM 中调度和执行批处理作业的环境来说非常方便。step.active
: 这个类型为 LongTaskTimer
的指标报告特定作业中当前活动的(即正在运行的)步骤。当一个作业包含多个步骤并且想知道当前正在处理哪个步骤时,这个指标非常有用。除了 Spring Batch 已在执行上下文持久化的运行时信息(如步骤类型、重启标志等)之外,此版本在执行上下文添加了一个重要细节,即用于序列化该上下文的 Spring Batch 版本。
虽然这看似一个细节,但在调试与执行上下文序列化和反序列化相关的升级问题时,它具有巨大的附加价值。
在此版本中,DefaultExecutionContextSerializer
已更新为将上下文序列化/反序列化为 Base64。
此外,通过 @EnableBatchProcessing
或 DefaultBatchConfiguration
配置的默认 ExecutionContextSerializer
已从 JacksonExecutionContextStringSerializer
更改为 DefaultExecutionContextSerializer
。现在对 Jackson 的依赖是可选的。为了使用 JacksonExecutionContextStringSerializer
,应将 jackson-core
添加到 classpath 中。
在此版本中,对 SystemCommandTasklet
进行了重新审视,并进行了如下更改:
引入了一个名为 CommandRunner
的新策略接口,以将命令执行与 Tasklet 执行解耦。默认实现是 JvmCommandRunner
,它使用 java.lang.Runtime#exec
API 运行系统命令。可以实现此接口以使用任何其他 API 运行系统命令。
运行命令的方法现在接受一个表示命令及其参数的 String
数组。不再需要对命令进行分词或进行任何预处理。此更改使 API 更加直观,并且更不容易出错。
直到版本 4,Spring Batch 仅支持 4 种可用作作业参数的类型,分别是 long
、double
、String
和 Date
。虽然这方便了框架端简化作业参数处理,但对用户端来说却带来了限制。例如,如果想使用 boolean
或自定义类型作为作业参数怎么办?这需要在 Spring Batch 中进行额外的转换,转换为受支持的类型之一,这很快就给用户带来了不便。
在此版本中,我们添加了支持将任何类型用作作业参数。此改进背后的主要变化如下:
---public class JobParameter implements Serializable {
+++public class JobParameter<T> implements Serializable {
--- private Object parameter;
+++ private T value;
--- private ParameterType parameterType;
+++ private Class<T> type;
}
此更改会影响作业参数在数据库中的持久化方式。请查看迁移指南了解数据库 schema 更改。参数类型的完全限定名现在作为 String
持久化,参数值也是如此。字符串文字使用标准的 Spring 转换服务转换为参数类型。可以通过任何必需的转换器来丰富标准转换服务,以将用户特定类型与字符串文字相互转换。
v4 中作业参数的默认表示法规定如下:
[+|-]parameterName(parameterType)=parameterValue
其中 parameterType
是 [string,long,double,date]
之一。虽然这种表示法很简洁,但它存在一些限制,因为它与环境变量不太兼容,并且对 Spring Boot 不太友好。
在 v5 中,我们将默认表示法更改如下:
parameterName=parameterValue,parameterType,identificationFlag
其中 parameterType
是参数类型的完全限定名。例如,以下键/值对:
schedule.date=2022-12-12,java.time.LocalDate
将被转换为一个标识性作业参数,其类型为 java.time.LocalDate
,值为 2022-12-12
。注意,标识标志是可选的,默认为 true
。这种新的默认表示法非常适合大多数用例,但当值包含逗号等字符时可能不太方便。因此,我们引入了一种新的“扩展”表示法,其灵感来自 Spring Boot 的 Json Application Properties,其规定如下:
parameterName='{"value": "parameterValue", "type":"parameterType", "identifying": "booleanValue"}'
其中 parameterType
是参数类型的完全限定名。Spring Batch 提供了 JsonJobParametersConverter
来支持这种表示法。当然,也可以通过实现策略接口 JobParametersConverter
并在作业仓库和作业探索器中注册自定义实现来支持任何其他表示法。
我们认为 Spring Batch 中作业参数处理的这两项主要更改更加方便、灵活且不容易出错。
在此版本中,@EnableBatchProcessing
注解引入了新属性,用于指定应该使用哪些组件和参数来配置批处理基础设施 Bean。例如,你现在可以指定 Spring Batch 在作业仓库中应配置哪个数据源和事务管理器。以下代码片段展示了这种配置的新方式:
@Configuration
@EnableBatchProcessing(dataSourceRef = "batchDataSource", transactionManagerRef = "batchTransactionManager")
public class MyJobConfiguration {
@Bean
public Job job(JobRepository jobRepository) {
return new JobBuilder("myJob", jobRepository)
//define job flow as needed
.build();
}
}
在此示例中,注入到 Job
Bean 定义中的 JobRepository
Bean 是在 DefaultBatchConfiguration
类中定义的。你可以通过覆盖相应的 getter 来指定自定义参数。例如,以下示例展示了如何覆盖作业仓库和作业探索器中使用的默认字符编码:
@Configuration
@EnableBatchProcessing
public class MyJobConfigWithCustomSerializer {
@Bean
public BatchConfigurer batchConfigurer() {
return new DefaultBatchConfigurer() {
@Override
public JobRepository getJobRepository() {
JobRepositoryFactoryBean factory = new JobRepositoryFactoryBean();
factory.setSerializer(createCustomSerializer());
// set other properties on the factory bean
try {
factory.afterPropertiesSet();
return factory.getObject();
} catch (Exception e) {
throw new RuntimeException(e);
}
}
@Override
public JobExplorer getJobExplorer() {
JobExplorerFactoryBean factoryBean = new JobExplorerFactoryBean();
factoryBean.setSerializer(createCustomSerializer());
// set other properties on the factory bean
try {
factoryBean.afterPropertiesSet();
return factoryBean.getObject();
} catch (Exception e) {
throw new RuntimeException(e);
}
}
private ExecutionContextSerializer createCustomSerializer() {
Jackson2ExecutionContextStringSerializer serializer = new Jackson2ExecutionContextStringSerializer();
// customize serializer
return serializer;
}
};
}
}
在 Spring Batch v5 中,你可以按如下方式提供自定义序列化器:
@Configuration
@EnableBatchProcessing(executionContextSerializerRef = "myCustomSerializer")
public class MyJobConfigWithCustomSerializer {
@Bean
public Job job(JobRepository jobRepository) {
return new JobBuilder("myJob", jobRepository)
//define job flow as needed
.build();
}
@Bean
public ExecutionContextSerializer myCustomSerializer() {
Jackson2ExecutionContextStringSerializer serializer = new Jackson2ExecutionContextStringSerializer();
// customize serializer
return serializer;
}
}
我们认为这种新的 Spring Batch 配置方式更加直观、直接且不容易出错。
在此版本中,你可以使用一个名为 DefaultBatchConfiguration
的新配置类,作为使用 @EnableBatchProcessing
配置基础设施 Bean 的替代方案。此类提供了默认配置的基础设施 Bean,你可以根据需要进行自定义。以下代码片段展示了此类的一个典型用法:
@Configuration
class MyJobConfiguration extends DefaultBatchConfiguration {
@Bean
public Job job(JobRepository jobRepository) {
return new JobBuilder("myJob", jobRepository)
//define job flow as needed
.build();
}
}
在此示例中,注入到 Job
Bean 定义中的 JobRepository
Bean 是在 DefaultBatchConfiguration
类中定义的。你可以通过覆盖相应的 getter 来指定自定义参数。例如,以下示例展示了如何覆盖作业仓库和作业探索器中使用的默认字符编码:
@Configuration
class MyJobConfiguration extends DefaultBatchConfiguration {
@Bean
public Job job(JobRepository jobRepository) {
return new JobBuilder("job", jobRepository)
// define job flow as needed
.build();
}
@Override
protected Charset getCharset() {
return StandardCharsets.ISO_8859_1;
}
}
此版本在通过 JobExplorerFactoryBean
创建的 JobExplorer
中引入了事务支持。现在你可以指定在查询批处理元数据时使用哪个事务管理器来驱动只读事务。此外,你现在还可以自定义事务属性。通过一个新的工厂 Bean,名为 JobOperatorFactoryBean
,向 JobOperator
添加了相同的事务支持。
截至版本 4,EnableBatchProcessing
注解提供了启动 Spring Batch 作业所需的所有基本基础设施 Bean。但是,它没有注册作业操作器 Bean,而作业操作器是停止、重启和放弃作业执行的主要入口点。
虽然这些工具的使用频率不如启动作业高,但在应用程序上下文中自动添加作业操作器有助于避免最终用户手动配置此类 Bean。
直到版本 4.3,JobLauncherTestUtils
习惯于自动装配被测作业,以简化测试设置。但如果在测试上下文中定义了多个作业怎么办?如果根本没有定义 Job
Bean 怎么办?因此,虽然这种自动装配在大多数情况下很方便,但在上述情况下却导致了一些问题。在此版本中,根据社区反馈,我们决定移除 JobLauncherTestUtils
中任何作业的自动装配。
类似地,JobRepositoryTestUtils
习惯于从应用程序上下文自动装配 DataSource
。同样,如果在测试上下文中没有定义数据源或定义了多个数据源怎么办?在此版本中,JobRepositoryTestUtils
已更新为针对 JobRepository
接口工作,而无需处理仓库的任何实现细节(例如数据源)。
如果你在测试上下文中手动定义这些工具 Bean,或者通过 @SpringBatchTest
导入它们,则当测试上下文中定义了这些类型的多个 Bean 时,你需要手动设置被测作业或测试数据源。
在此版本中,Spring Batch 的整个测试套件已迁移到 JUnit 5。虽然这不会直接影响最终用户,但它有助于批处理团队以及社区贡献者使用下一代 JUnit 编写更好的测试。
对将 Java Record 作为面向块的步骤中的项的支持最初是在 v4.3 中引入的,但由于 v4 的基线是 Java 8,该支持受到限制。在 Java 8 中,Record 甚至还没有进入预览阶段。最初的支持是基于反射技巧来创建 Java Record 并用数据填充它们,当时还无法访问在 Java 16 中最终确定的 java.lang.Record
API。
现在 v5 的基线是 Java 17,我们通过在框架的不同部分利用 java.lang.Record
API 来改进了 Spring Batch 中的 Record 支持。例如,FlatFileItemReaderBuilder
现在能够检测项类型是 Record 还是常规类,并相应地配置相应的 FieldSetMapper
实现(Record 使用 RecordFieldSetMapper
,常规类使用 BeanWrapperFieldSetMapper
)。这里的目标是让所需的 FieldSetMapper
类型的配置对用户来说是透明的。在 FlatFileItemWriterBuilder
中也实现了相同的功能,以便根据项类型配置 RecordFieldExtractor
或 BeanWrapperFieldExtractor
。
多年来,在框架的不同领域报告了几个与字符编码相关的问题,例如基于文件的 ItemReader 和 ItemWriter 之间的默认编码不一致、处理执行上下文中的多字节字符时的序列化/反序列化问题等。
本着与 JEP 400 相同的精神,并遵循 UTF-8 宣言,我们将框架所有领域的默认编码更改为 UTF-8
,并在适当的地方使此默认值可配置。
我们借此重要版本发布的机会,利用 Java 8+ 的特性改进了代码库,例如:
@FunctionalInterface
(参见 issue 4107)此功能已被多次请求,并最终在此版本中发布。现在可以使用新添加的 Maven BOM 来导入 Spring Batch 模块,并保持一致的版本号。
直到 v4.3,Spring Batch 通过将 MariaDB 视为 MySQL 来提供支持。在此版本中,MariaDB 现在被视为一个独立的数据库产品,拥有自己的 DDL 脚本和 DataFieldMaxValueIncrementer
。
SAP Hana 现在已正式支持作为 Spring Batch 中的作业仓库。
在此版本中,文档已更新为使用 Spring Asciidoctor Backend。此后端确保所有项目都遵循相同的文档风格。为了与其他项目保持一致,在此版本中,Spring Batch 的参考文档已更新为使用此后端。您可以在此处查看参考文档的新版本。
在此主版本中,之前版本中所有已弃用的 API 都已被移除。此外,一些 API 在 v5.0 中已被弃用,并计划在 v5.2 中移除。最后,出于实际原因,一些 API 被移动或移除而未进行弃用标记。有关所有已弃用 API 的列表,请参阅迁移指南。
SQLFire 已宣布于 2014 年 11 月 1 日结束生命周期 (EOL)。对 SQLFire 作为作业仓库的支持在 v4.3 版本中被弃用,并在 v5.0 版本中被移除。
根据停止维护的决定,对 Spring Batch 中 Apache Geode 的支持已被移除。
代码已作为社区驱动的工作转移到 spring-batch-extensions 仓库。
由于采用率不高,在此版本中已停止维护 JSR-352 的实现。
有些错误无法修复,除非引入破坏性变更。我们借此主版本的机会修复了这些错误。有关此版本中修复的 40 多个错误的完整列表,请参阅发行说明!
我要感谢所有为此巨大版本做出贡献的贡献者们!如果没有出色的 Spring 社区(特别是 Spring Batch 社区)的帮助,这个版本是不可能实现的。我们很高兴听到您对此主版本的反馈,以及它如何能够改善您的批处理基础设施。请在 Github、Twitter 和 StackOverflow 上提交您的反馈意见。
由于我们刚刚发布了下一代 Spring Batch 的第一个版本,我们仍然有大量正在开发或计划在下一版本中开发的想法和功能,例如:
我们将在不久的将来与您分享完整的路线图,并展示如何参与这些新功能的早期开发和测试。敬请关注!