Spring Batch 5.0 正式发布!

发布 | Mahmoud Ben Hassine | 2022年11月24日 | ...

它终于来了!Spring Batch 5.0 现已从 Maven Central 正式发布。Spring Batch 5 是两年工作的成果,包括 50 多位贡献者做出的数十项改进、功能和错误修复!我谨代表团队感谢所有参与此重大发布的贡献者!

这篇博文将介绍此框架新一代的主要亮点。您可以在发行说明中找到所有更改的详细信息,并在迁移指南中找到升级说明。

新增功能?

  • 新的 Java 版本基线
  • 主要依赖项升级
  • 完全支持 GraalVM 原生
  • 引入 Micrometer 的新观察 API
  • 执行上下文元数据改进
  • 新的默认执行上下文序列化格式
  • SystemCommandTasklet 增强功能
  • 添加对使用任何类型作为作业参数的支持
  • 改进的作业参数转换
  • EnableBatchProcessing 中的新注解属性
  • 基础设施 Bean 的新配置类
  • JobExplorer 和 JobOperator 中的事务支持
  • 使用 EnableBatchProcessing 自动注册 JobOperator
  • 测试实用程序配置更新
  • 迁移到 JUnit Jupiter
  • Java 记录支持改进
  • 默认使用 UTF-8
  • Java 8 功能更新
  • 新的 Maven 物料清单
  • 完全支持 MariaDB
  • 支持 SAP HANA 作为作业存储库
  • 改进的文档

新的 Java 版本基线

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 正在全面更新依赖项到以下版本:

  • Spring Framework 6
  • Spring Integration 6
  • Spring Data 3
  • Spring AMQP 3
  • Spring for Apache Kafka 3
  • Micrometer 1.10

此版本还标志着迁移到:

  • Jakarta EE 9
  • Hibernate 6

完全支持 GraalVM 原生

为使用 GraalVM native-image 编译器将 Spring Batch 应用程序编译为原生可执行文件提供支持的工作始于 v4.2,并在 v4.3 中作为实验性功能发布。

在此版本中,通过提供必要的提前 (Ahead-Of-Time) 处理和运行时提示以使用 GraalVM 本地编译 Spring Batch 应用程序,原生支持得到了显着改进。

在此博文中,我们想与您分享我们在该领域进行的一些基准测试。以下基准测试基于batch示例(来自Spring Native示例项目)。这些基准测试显示了使用常规 JVM 和作为原生可执行文件执行的相同批处理应用程序的启动时间和总执行时间的比较。

perf-native

此处显示的值是使用以下软件和硬件设置对样本执行 10 次的平均值:

  • JVM:OpenJDK 版本“17” 2021-09-14
  • GraalVM:OpenJDK 运行时环境 GraalVM CE 22.0.0.2
  • MacOS BigSur v11.6.2(CPU:2,4 GHz 8 核 Intel Core i9,内存:32 GB 2667 MHz DDR4)

如这些基准测试所示,原生 Spring Batch 应用程序的启动速度提高了两倍,运行时速度提高了近十倍!这对于云原生批处理工作负载来说确实是一个改变游戏规则的功能!

引入 Micrometer 的新观察 API

随着升级到 Micrometer 1.10,您现在除了批处理指标之外还可以获得批处理跟踪。Spring Batch 将为每个作业创建一个跨度,并为作业中的每个步骤创建一个跨度。此跟踪元数据可以在仪表板上收集和查看,例如Zipkin

此外,此版本引入了新的指标:

  • job.launch.count:这是一个Counter,报告通过JobLauncher启动了多少个作业。这对于批处理作业在持续运行的 JVM 中调度和执行的环境非常方便。
  • step.active:此LongTaskTimer类型的指标报告特定作业中当前活动的(即正在运行的)步骤。此指标在作业有多个步骤并且想要知道处理当前发生在哪个步骤的情况下很有用。

执行上下文元数据改进

除了 Spring Batch 已经在执行上下文中关于运行时信息(如步骤类型、重启标志等)持久化存储的内容之外,此版本还在执行上下文中添加了一个重要的细节,即用于序列化上下文的 Spring Batch 版本。

虽然这看起来是一个细节,但在调试与执行上下文序列化和反序列化相关的升级问题时,它具有巨大的附加价值。

新的默认执行上下文序列化格式

在此版本中,DefaultExecutionContextSerializer已更新为将上下文序列化/反序列化为/从 Base64。

此外,@EnableBatchProcessingDefaultBatchConfiguration配置的默认ExecutionContextSerializer已从JacksonExecutionContextStringSerializer更改为DefaultExecutionContextSerializer。现在 Jackson 依赖项是可选的。为了使用JacksonExecutionContextStringSerializer,应将jackson-core添加到类路径中。

SystemCommandTasklet 增强功能

在此版本中重新审视了SystemCommandTasklet,并进行了如下更改:

  • 引入了一个名为CommandRunner的新策略接口,以便将命令执行与任务执行分离。默认实现是JvmCommandRunner,它使用java.lang.Runtime#exec API 运行系统命令。可以实现此接口以使用任何其他 API 运行系统命令。

  • 现在,运行命令的方法接受一个表示命令及其参数的String数组。无需再对命令进行标记化或进行任何预处理。此更改使 API 更直观,并且更不容易出错。

支持使用任何类型作为作业参数

在 4.x 版本之前,Spring Batch 仅支持 4 种类型作为作业参数,分别是 longdoubleStringDate。虽然这简化了框架侧的作业参数处理,但也限制了用户的使用。例如,如果用户想使用 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;

}

此更改会影响作业参数在数据库中的持久化方式。请查看 迁移指南了解数据库模式的更改。参数类型的全限定名称现在作为 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 应用属性 的启发,并指定如下:

parameterName='{"value": "parameterValue", "type":"parameterType", "identifying": "booleanValue"}'

其中 parameterType 是参数类型的全限定名称。Spring Batch 提供了 JsonJobParametersConverter 来支持此表示法。当然,可以通过实现策略接口 JobParametersConverter 并将自定义实现注册到作业存储库和作业资源管理器中来支持任何其他表示法。

我们相信 Spring Batch 中这两项关于作业参数处理的主要更改更加方便、灵活,并且更不容易出错。

@EnableBatchProcessing 注解的新属性

在本版本中,@EnableBatchProcessing 注解引入了新的属性来指定哪些组件和参数应该用于配置 Batch 基础设施 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();
	}

}

在此示例中,batchDataSourcebatchTransactionManager 指的是应用上下文中的 Bean,它们用于配置作业存储库和作业资源管理器。您不再需要定义自定义的 BatchConfiguer,该类已在本版本中移除。例如,在 Spring Batch v4 中,可以通过提供自定义的 BatchConfigurer 来提供自定义的执行上下文序列化器,如下所示:

@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 的方式更加直观、简单,并且更不容易出错。

用于基础设施 Bean 的新配置类

在本版本中,您可以使用一个名为 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 中引入了事务支持。您现在可以指定哪个事务管理器用于在查询批处理元数据时驱动只读事务。此外,您现在还可以自定义事务属性。通过一个名为 JobOperatorFactoryBean 的新工厂 Bean,同样的事务支持也添加到 JobOperator 中。

使用 @EnableBatchProcessing 自动注册作业操作器

从 4.x 版本开始,@EnableBatchProcessing 注解提供了启动 Spring Batch 作业所需的所有基本基础设施 Bean。但是,它没有注册作业操作器 Bean,它是停止、重新启动和放弃作业执行的主要入口点。

虽然这些实用程序不像启动作业那样经常使用,但在应用上下文中自动添加作业操作器可以避免最终用户手动配置此 Bean,从而非常有用。

测试实用程序配置更新

在 4.3 版本之前,JobLauncherTestUtils 用于自动装配正在测试的作业,以便于测试设置。但是,如果测试上下文中定义了多个作业怎么办?如果根本没有定义 Job Bean 怎么办?因此,虽然这种自动装配在大多数情况下都很方便,但事实证明它在上述情况下会导致一些问题。在本版本中,根据社区的反馈,我们决定移除 JobLauncherTestUtils 中任何作业的自动装配。

类似地,JobRepositoryTestUtils 用于从应用上下文中自动装配 DataSource。同样,如果测试上下文中没有定义数据源或定义了多个数据源怎么办?在此版本中,JobRepositoryTestUtils 已更新为针对 JobRepository 接口工作,无需处理存储库的任何实现细节(例如数据源)。

如果您在测试上下文中手动定义这些实用程序 Bean 或通过 @SpringBatchTest 导入它们,则当测试上下文中定义了多个这些类型的 Bean 时,您将手动设置正在测试的作业或测试数据源。

迁移到 JUnit Jupiter

在本版本中,Spring Batch 的整个测试套件已迁移到 JUnit 5。虽然这不会直接影响最终用户,但它可以帮助 Batch 团队以及社区贡献者使用下一代 JUnit 来编写更好的测试。

Java Records 支持改进

在 v4.3 中最初引入了对 Java 记录作为分块导向步骤中的项的支持,但由于 v4 以 Java 8 作为基线,因此该支持有限。在 Java 8 中,记录甚至还没有预览版。最初的支持是基于反射技巧来创建 Java 记录并使用数据填充它们,而无需访问在 Java 16 中最终确定的 java.lang.Record API。

现在 v5 以 Java 17 作为基线,我们通过在框架的不同部分利用 java.lang.Record API 改进了 Spring Batch 中的记录支持。例如,FlatFileItemReaderBuilder 现在能够检测项目类型是记录还是普通类,并相应地配置相应的 FieldSetMapper 实现(记录使用 RecordFieldSetMapper,普通类使用 BeanWrapperFieldSetMapper)。此处的目标是使所需 FieldSetMapper 类型的配置对用户透明。相同的特性也已在 FlatFileItemWriterBuilder 中实现,以便根据项目类型配置 RecordFieldExtractorBeanWrapperFieldExtractor

默认使用 UTF-8

多年来,在框架的不同领域报告了许多与字符编码相关的问题,例如基于文件的项目读取器和写入器之间不一致的默认编码、处理执行上下文中的多字节字符时的序列化/反序列化问题等。

本着与JEP 400相同的精神,并遵循UTF-8 宣言,我们在框架的所有领域都将默认编码更改为 UTF-8,并在适当的地方使此默认值可配置。

Java 8 功能更新

我们借此主要版本的机会,使用 Java 8 及更高版本的功能来改进代码库,例如

  • 在接口中使用默认方法并弃用“支持”类(参见问题 3924
  • 在公共 API 中适当地添加 @FunctionalInterface(参见问题 4107
  • 添加支持将日期和时间 API 中的类型用作作业参数。(参见问题 1035

新的 Maven 物料清单

此功能已多次被请求,并最终在此版本中发布。现在可以使用新添加的 Maven BOM 以一致的版本号导入 Spring Batch 模块。

完全支持 MariaDB

在 v4.3 之前,Spring Batch 通过将 MariaDB 视为 MySQL 来提供对它的支持。在此版本中,MariaDB 现在被视为一个独立的数据库产品,具有自己的 DDL 脚本和 DataFieldMaxValueIncrementer

支持将 SAP HANA 作为作业存储库

SAP Hana 现在在 Spring Batch 中正式支持作为作业存储库。

改进的文档

在此版本中,文档已更新为使用Spring Asciidoctor 后端。此后端确保产品组合中的所有项目都遵循相同的文档风格。为了与其他项目保持一致,Spring Batch 的参考文档已在此版本中更新为使用此后端。您可以此处查看参考文档的新版本。

弃用或移除的内容?

在此主要版本中,先前版本中弃用的所有 API 都已移除。此外,一些 API 在 v5.0 中已弃用,并计划在 v5.2 中移除。最后,出于实际原因,一些 API 已移动或移除,而无需弃用。有关所有弃用 API 的列表,请参阅迁移指南

移除 SQLFire 支持

SQLFire 已于 2014 年 11 月 1 日宣布停止使用。v4.3 版本中已弃用 SQLFire 作为作业存储库的支持,并在 v5.0 版本中移除。

移除 GemFire 支持

根据停止支持 Spring Data for Apache Geode 的决定,已移除 Spring Batch 中对 Apache Geode 的支持。

代码已作为社区驱动的努力移至spring-batch-extensions存储库。

移除 JSR-352 实现

由于采用率不足,在此版本中已停止使用 JSR-352 的实现。

已修复的内容?

一些错误无法在不引入重大更改的情况下修复。我们借此主要版本的机会修复此类错误。请参阅发行说明,了解在此版本中修复的 40 多个错误的完整列表!

反馈和贡献

我要感谢所有参与此重大版本的贡献者!如果没有整个 Spring 社区,特别是 Spring Batch 社区的帮助,这个版本是不可能实现的。我们很乐意听取您对这个主要版本的反馈,以及它如何改进您的批处理基础设施。请在GithubTwitterStackOverflow上提交您的反馈。

下一步是什么?

由于我们刚刚发布了下一代 Spring Batch 的第一个版本,我们仍然有很多想法和功能正在开发中或计划在下一个版本中开发,例如

  • 分块导向处理模型的新实现
  • 基于 Java 19 虚拟线程的新并发模型
  • 基于 MongoDB 的新的作业存储库实现
  • 以及更多!

我们将在不久的将来与您分享我们的完整路线图,并向您展示如何参与这些新功能的早期开发和测试阶段。敬请期待!


Spring Batch 主页|GitHub 上的源代码|参考文档

获取 Spring 时事通讯

关注 Spring 时事通讯

订阅

抢先一步

VMware 提供培训和认证,助您快速提升技能。

了解更多

获取支持

Tanzu Spring 提供 OpenJDK™、Spring 和 Apache Tomcat® 的支持和二进制文件,只需一个简单的订阅即可。

了解更多

即将举行的活动

查看 Spring 社区中所有即将举行的活动。

查看全部