JobStep 属性的延迟绑定

前面展示的 XML 和平面文件示例都使用了 Spring Resource 抽象来获取文件。之所以可行,是因为 Resource 提供了一个返回 java.io.FilegetFile 方法。您可以使用标准的 Spring 构造来配置 XML 和平面文件资源:spring-doc.cadn.net.cn

以下示例展示了 Java 中的后期绑定:spring-doc.cadn.net.cn

Java 配置
@Bean
public FlatFileItemReader flatFileItemReader() {
	FlatFileItemReader<Foo> reader = new FlatFileItemReaderBuilder<Foo>()
			.name("flatFileItemReader")
			.resource(new FileSystemResource("file://outputs/file.txt"))
			...
}

以下示例展示了 XML 中的后期绑定:spring-doc.cadn.net.cn

XML 配置
<bean id="flatFileItemReader"
      class="org.springframework.batch.infrastructure.item.file.FlatFileItemReader">
    <property name="resource"
              value="file://outputs/file.txt" />
</bean>

上述 Resource 会从指定的文件系统位置加载文件。请注意,绝对路径必须以双斜杠(//)开头。在大多数 Spring 应用程序中,此方案已足够适用,因为这些资源的名称在编译时即已知晓。然而,在批处理场景中,文件名可能需要在运行时作为作业参数动态确定。这一问题可以通过使用 -D 参数读取系统属性来解决。spring-doc.cadn.net.cn

以下展示了如何在 Java 中从属性读取文件名:spring-doc.cadn.net.cn

Java 配置
@Bean
public FlatFileItemReader flatFileItemReader(@Value("${input.file.name}") String name) {
	return new FlatFileItemReaderBuilder<Foo>()
			.name("flatFileItemReader")
			.resource(new FileSystemResource(name))
			...
}

以下示例展示了如何从 XML 属性中读取文件名:spring-doc.cadn.net.cn

XML 配置
<bean id="flatFileItemReader"
      class="org.springframework.batch.infrastructure.item.file.FlatFileItemReader">
    <property name="resource" value="${input.file.name}" />
</bean>

要使此解决方案生效,只需一个系统参数(例如 -Dinput.file.name="file://outputs/file.txt")。spring-doc.cadn.net.cn

尽管您可以在此处使用 PropertyPlaceholderConfigurer,但如果系统属性始终已设置,则并非必需,因为 Spring 中的 ResourceEditor 已经会对系统属性进行过滤并执行占位符替换。

通常,在批处理场景中,更倾向于在作业的JobParameters中参数化文件名(而不是通过系统属性),并以这种方式访问它们。为实现这一点,Spring Batch 允许对各种JobStep属性进行延迟绑定。spring-doc.cadn.net.cn

以下示例展示了如何在 Java 中对文件名进行参数化:spring-doc.cadn.net.cn

Java 配置
@StepScope
@Bean
public FlatFileItemReader flatFileItemReader(@Value("#{jobParameters['input.file.name']}") String name) {
	return new FlatFileItemReaderBuilder<Foo>()
			.name("flatFileItemReader")
			.resource(new FileSystemResource(name))
			...
}

以下示例展示了如何在 XML 中对文件名进行参数化:spring-doc.cadn.net.cn

XML 配置
<bean id="flatFileItemReader" scope="step"
      class="org.springframework.batch.infrastructure.item.file.FlatFileItemReader">
    <property name="resource" value="#{jobParameters['input.file.name']}" />
</bean>

你可以用同样的方式访问 JobExecutionStepExecution 级别的 ExecutionContextspring-doc.cadn.net.cn

以下示例展示了如何在 Java 中访问 ExecutionContextspring-doc.cadn.net.cn

Java 配置
@StepScope
@Bean
public FlatFileItemReader flatFileItemReader(@Value("#{jobExecutionContext['input.file.name']}") String name) {
	return new FlatFileItemReaderBuilder<Foo>()
			.name("flatFileItemReader")
			.resource(new FileSystemResource(name))
			...
}
Java 配置
@StepScope
@Bean
public FlatFileItemReader flatFileItemReader(@Value("#{stepExecutionContext['input.file.name']}") String name) {
	return new FlatFileItemReaderBuilder<Foo>()
			.name("flatFileItemReader")
			.resource(new FileSystemResource(name))
			...
}

以下示例展示了如何在 XML 中访问 ExecutionContextspring-doc.cadn.net.cn

XML 配置
<bean id="flatFileItemReader" scope="step"
      class="org.springframework.batch.infrastructure.item.file.FlatFileItemReader">
    <property name="resource" value="#{jobExecutionContext['input.file.name']}" />
</bean>
XML 配置
<bean id="flatFileItemReader" scope="step"
      class="org.springframework.batch.infrastructure.item.file.FlatFileItemReader">
    <property name="resource" value="#{stepExecutionContext['input.file.name']}" />
</bean>
任何使用延迟绑定的 bean 必须声明为 scope="step"。更多信息请参阅 步骤作用域(Step Scope)Step bean 不应设置为步骤作用域。如果在步骤定义中需要延迟绑定,则应将该步骤的组件(如 tasklet、item reader/writer 等)设置为相应的作用域。如果无法做到这一点(例如,该步骤实现未使用任何可设置为步骤作用域的批处理构件),则可以将步骤本身设置为作业作用域(job-scoped)。 一个典型的例子是在 ChunkOrientedStep 中根据作业参数动态绑定块大小(chunk size)。更多信息请参阅 作业作用域(Job Scope)
如果您使用 Spring 3.0(或更高版本),步骤作用域 Bean 中的表达式将采用 Spring 表达式语言(SpEL),这是一种功能强大的通用语言,具备许多有趣的特性。为了提供向后兼容性,如果 Spring Batch 检测到存在较旧版本的 Spring,它将使用一种原生表达式语言,该语言功能较弱且解析规则略有不同。主要区别在于:在上述示例中,使用 Spring 2.5 时映射的键无需加引号,但在 Spring 3.0 中引号是必需的。

步骤作用域

前面展示的所有后期绑定示例都在 bean 定义上声明了 step 的作用域。spring-doc.cadn.net.cn

以下示例展示了在 Java 中绑定到步骤作用域的示例:spring-doc.cadn.net.cn

Java 配置
@StepScope
@Bean
public FlatFileItemReader flatFileItemReader(@Value("#{jobParameters[input.file.name]}") String name) {
	return new FlatFileItemReaderBuilder<Foo>()
			.name("flatFileItemReader")
			.resource(new FileSystemResource(name))
			...
}

以下示例展示了在 XML 中绑定到步骤作用域的示例:spring-doc.cadn.net.cn

XML 配置
<bean id="flatFileItemReader" scope="step"
      class="org.springframework.batch.infrastructure.item.file.FlatFileItemReader">
    <property name="resource" value="#{jobParameters[input.file.name]}" />
</bean>

使用 Step 的作用域是进行延迟绑定所必需的,因为直到 Step 启动后,才能实际实例化该 Bean 以找到其属性。由于默认情况下它不属于 Spring 容器,因此必须通过以下方式显式添加作用域:使用 batch 命名空间、显式包含针对 StepScope 的 Bean 定义,或使用 @EnableBatchProcessing 注解。请仅选用其中一种方法。以下示例使用了 batch 命名空间:spring-doc.cadn.net.cn

<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:batch="http://www.springframework.org/schema/batch"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="...">
<batch:job .../>
...
</beans>

以下示例明确包含了 Bean 定义:spring-doc.cadn.net.cn

<bean class="org.springframework.batch.core.scope.StepScope" />

工作范围

Job 作用域在 Spring Batch 3.0 中引入,类似于配置中的 Step 作用域,但它是针对 Job 上下文的作用域,因此每个运行的作业仅存在一个此类 bean 实例。此外,通过使用 #{..} 占位符,还支持从 JobContext 访问的引用的延迟绑定。利用此功能,您可以从作业或作业执行上下文以及作业参数中提取 bean 属性。spring-doc.cadn.net.cn

以下示例展示了如何在基于块(chunk-oriented)的步骤中,通过在 Java 中使用作业作用域(job scope),从作业参数动态绑定块大小:spring-doc.cadn.net.cn

Java 配置
@Bean
@JobScope
public Step step(JobRepository jobRepository, @Value("#{jobParameters['chunkSize']}") int chunkSize) {
    return new StepBuilder(jobRepository)
            .<Integer, Integer>chunk(chunkSize)
            .reader(...)
            .writer(...)
            .build();
}
Java 配置
@Bean
@JobScope
public Step step(JobRepository jobRepository, @Value("#{jobExecutionContext['chunkSize']}") int chunkSize) {
    return new StepBuilder(jobRepository)
            .<Integer, Integer>chunk(chunkSize)
            .reader(...)
            .writer(...)
            .build();
}

以下示例展示了在 XML 中绑定到 job 作用域的示例:spring-doc.cadn.net.cn

XML 配置
<bean id="..." class="..." scope="job">
    <property name="name" value="#{jobParameters[chunkSize]}" />
</bean>
XML 配置
<bean id="..." class="..." scope="job">
    <property name="name" value="#{jobExecutionContext['chunkSize']}.txt" />
</bean>

由于默认情况下它不是 Spring 容器的一部分,因此必须通过以下方式显式添加作用域:使用 batch 命名空间、为 JobScope 显式包含一个 Bean 定义,或使用 @EnableBatchProcessing 注解(仅选择其中一种方法)。 以下示例使用了 batch 命名空间:spring-doc.cadn.net.cn

<beans xmlns="http://www.springframework.org/schema/beans"
		  xmlns:batch="http://www.springframework.org/schema/batch"
		  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
		  xsi:schemaLocation="...">

<batch:job .../>
...
</beans>

以下示例包含一个显式定义 JobScope 的 bean:spring-doc.cadn.net.cn

<bean class="org.springframework.batch.core.scope.JobScope" />
在多线程或分区步骤中使用作业作用域(job-scoped)的 Bean 存在一些实际限制。Spring Batch 并不控制这些用例中生成的线程,因此无法正确配置它们以使用此类 Bean。因此,我们不建议在多线程或分区步骤中使用作业作用域的 Bean。

作用域ItemStream组件

当使用 Java 配置风格来定义作业或步骤作用域的 ItemStream Bean 时, Bean 定义方法的返回类型应至少为 ItemStream。这是必需的, 以便 Spring Batch 能够正确创建实现该接口的代理,从而 通过按预期调用 openupdateclose 方法来履行其契约。spring-doc.cadn.net.cn

建议此类 bean 的定义方法返回最具体的已知实现,如下例所示:spring-doc.cadn.net.cn

定义一个具有最具体返回类型的步骤作用域 Bean
@Bean
@StepScope
public FlatFileItemReader flatFileItemReader(@Value("#{jobParameters['input.file.name']}") String name) {
	return new FlatFileItemReaderBuilder<Foo>()
			.resource(new FileSystemResource(name))
			// set other properties of the item reader
			.build();
}