跳到主要内容
版本:6.0.2

JobStep 属性的延迟绑定

DeepSeek V3 中英对照 Late Binding of Job and Step Attributes Late Binding of Job and Step Attributes

前面展示的XML和平面文件示例都使用了Spring的Resource抽象来获取文件。这种方式之所以有效,是因为Resource接口提供了返回java.io.FilegetFile方法。您可以通过标准的Spring配置方式来配置XML和平面文件资源:

以下示例展示了 Java 中的延迟绑定:

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

前面的 Resource 从指定的文件系统位置加载文件。请注意,绝对路径必须以双斜杠 (//) 开头。在大多数 Spring 应用中,这个解决方案已经足够好,因为这些资源的名称在编译时是已知的。然而,在批处理场景中,文件名可能需要作为作业的参数在运行时确定。这可以通过使用 -D 参数读取系统属性来解决。

以下展示了如何在 Java 中从属性读取文件名:

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

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

备注

尽管你可以在这里使用 PropertyPlaceholderConfigurer,但如果系统属性始终被设置,则没有必要这样做,因为 Spring 中的 ResourceEditor 已经对系统属性进行了过滤和占位符替换。

在批处理场景中,通常更倾向于在作业的 JobParameters 中参数化文件名(而非通过系统属性),并通过这种方式访问它们。为实现此目的,Spring Batch 支持对多种 JobStep 属性进行延迟绑定。

以下示例展示了如何在 Java 中对文件名进行参数化:

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

你可以以相同的方式访问 JobExecutionStepExecution 级别的 ExecutionContext

以下示例展示了如何在 Java 中访问 ExecutionContext

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

任何使用延迟绑定的 bean 都必须通过 scope="step" 来声明。更多信息请参阅 Step Scope。一个 Step bean 不应被定义为 step 作用域或 job 作用域。如果在 step 定义中需要延迟绑定,那么该 step 的组件(如 tasklet、item reader/writer、completion policy 等)才应该被设定为相应作用域。

备注

如果您使用的是 Spring 3.0(或更高版本),则步骤作用域 Bean 中的表达式采用 Spring 表达式语言,这是一种功能强大的通用语言,具有许多有趣的特性。为了提供向后兼容性,如果 Spring Batch 检测到存在旧版本的 Spring,它会使用功能较弱且解析规则略有不同的原生表达式语言。主要区别在于,在上面的示例中,映射键在 Spring 2.5 中不需要加引号,但在 Spring 3.0 中引号是必需的。

步骤范围

之前展示的所有延迟绑定示例都在 bean 定义上声明了 step 作用域。

以下示例展示了在 Java 中绑定到步骤作用域的示例:

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

使用 Step 作用域是实现延迟绑定的必要条件,因为在实际启动 Step 之前无法实例化该 Bean,这样才能找到相应的属性。由于默认情况下它不属于 Spring 容器,因此必须通过以下方式显式添加作用域:使用 batch 命名空间、显式包含 StepScope 的 Bean 定义,或使用 @EnableBatchProcessing 注解。注意仅需选择其中一种方法。以下示例展示了使用 batch 命名空间的方式:

<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 定义:

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

工作范围

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

以下示例展示了在 Java 中绑定到作业作用域的示例:

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

由于默认情况下它不属于 Spring 容器的一部分,因此必须通过使用 batch 命名空间、显式包含 JobScope 的 bean 定义或使用 @EnableBatchProcessing 注解(仅选择一种方法)来显式添加作用域。以下示例使用 batch 命名空间:

<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:

<bean class="org.springframework.batch.core.scope.JobScope" />
备注

在多线程或分区步骤中使用作业作用域 Bean 存在一些实际限制。Spring Batch 无法控制这些场景中生成的线程,因此无法正确配置这些线程以使用此类 Bean。因此,我们不建议在多线程或分区步骤中使用作业作用域 Bean。

限定 ItemStream 组件的作用域

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

建议将此类 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();
}