Job 和 Step 属性的延迟绑定
前面显示的 XML 和平面文件示例都使用 Spring 的 Resource
抽象来获取文件。这之所以有效,是因为 Resource
具有一个 getFile
方法,该方法返回一个 java.io.File
。您可以通过使用标准的 Spring 结构来配置 XML 和平面文件资源。
-
Java
-
XML
以下示例显示了 Java 中的延迟绑定。
@Bean
public FlatFileItemReader flatFileItemReader() {
FlatFileItemReader<Foo> reader = new FlatFileItemReaderBuilder<Foo>()
.name("flatFileItemReader")
.resource(new FileSystemResource("file://outputs/file.txt"))
...
}
以下示例显示了 XML 中的延迟绑定。
<bean id="flatFileItemReader"
class="org.springframework.batch.item.file.FlatFileItemReader">
<property name="resource"
value="file://outputs/file.txt" />
</bean>
前面的 Resource
从指定的文件系统位置加载文件。请注意,绝对位置必须以双斜杠 (//
) 开头。在大多数 Spring 应用程序中,此解决方案足够好,因为这些资源的名称在编译时是已知的。但是,在批处理场景中,可能需要在运行时将文件名作为作业的参数确定。这可以通过使用 -D
参数来读取系统属性来解决。
-
Java
-
XML
以下显示了如何在 Java 中从属性读取文件名。
@Bean
public FlatFileItemReader flatFileItemReader(@Value("${input.file.name}") String name) {
return new FlatFileItemReaderBuilder<Foo>()
.name("flatFileItemReader")
.resource(new FileSystemResource(name))
...
}
以下示例显示了如何在 XML 中从属性读取文件名。
<bean id="flatFileItemReader"
class="org.springframework.batch.item.file.FlatFileItemReader">
<property name="resource" value="${input.file.name}" />
</bean>
此解决方案要正常工作,只需要一个系统参数(例如 -Dinput.file.name="file://outputs/file.txt"
)。
虽然您可以在此处使用 PropertyPlaceholderConfigurer ,但如果始终设置系统属性,则没有必要,因为 Spring 中的 ResourceEditor 已经过滤并对系统属性执行了占位符替换。 |
通常,在批处理设置中,最好在作业的 JobParameters
中参数化文件名(而不是通过系统属性),并以这种方式访问它们。为此,Spring Batch 允许延迟绑定各种 Job
和 Step
属性。
-
Java
-
XML
以下示例显示了如何在 Java 中参数化文件名。
@StepScope
@Bean
public FlatFileItemReader flatFileItemReader(@Value("#{jobParameters['input.file.name']}") String name) {
return new FlatFileItemReaderBuilder<Foo>()
.name("flatFileItemReader")
.resource(new FileSystemResource(name))
...
}
以下示例显示了如何在 XML 中参数化文件名。
<bean id="flatFileItemReader" scope="step"
class="org.springframework.batch.item.file.FlatFileItemReader">
<property name="resource" value="#{jobParameters['input.file.name']}" />
</bean>
您可以以相同的方式访问 JobExecution
和 StepExecution
级别的 ExecutionContext
。
-
Java
-
XML
以下示例显示了如何在 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))
...
}
以下示例显示了如何在 XML 中访问 ExecutionContext
。
<bean id="flatFileItemReader" scope="step"
class="org.springframework.batch.item.file.FlatFileItemReader">
<property name="resource" value="#{jobExecutionContext['input.file.name']}" />
</bean>
<bean id="flatFileItemReader" scope="step"
class="org.springframework.batch.item.file.FlatFileItemReader">
<property name="resource" value="#{stepExecutionContext['input.file.name']}" />
</bean>
任何使用延迟绑定的 bean 必须使用 scope="step" 声明。有关更多信息,请参阅 步骤范围。Step bean 不应该具有步骤范围。如果在步骤定义中需要延迟绑定,则该步骤的组件(tasklet、项目读取器或写入器等)应该是应该设置范围的组件。 |
如果您使用 Spring 3.0(或更高版本),则步骤范围 bean 中的表达式位于 Spring 表达式语言中,这是一种功能强大的通用语言,具有许多有趣的特性。为了提供向后兼容性,如果 Spring Batch 检测到存在较旧版本的 Spring,它将使用功能较弱且解析规则略有不同的本机表达式语言。主要区别在于,上面的示例中的映射键在 Spring 2.5 中不需要用引号括起来,但在 Spring 3.0 中,引号是必需的。 |
步骤范围
前面显示的所有延迟绑定示例都在 bean 定义上声明了 step
范围。
-
Java
-
XML
以下示例显示了在 Java 中绑定到步骤范围的示例。
@StepScope
@Bean
public FlatFileItemReader flatFileItemReader(@Value("#{jobParameters[input.file.name]}") String name) {
return new FlatFileItemReaderBuilder<Foo>()
.name("flatFileItemReader")
.resource(new FileSystemResource(name))
...
}
以下示例显示了在 XML 中绑定到步骤范围的示例。
<bean id="flatFileItemReader" scope="step"
class="org.springframework.batch.item.file.FlatFileItemReader">
<property name="resource" value="#{jobParameters[input.file.name]}" />
</bean>
使用 Step
范围是使用延迟绑定所必需的,因为 bean 实际上直到 Step
开始才能实例化,以便找到属性。因为它默认不是 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" />
作业范围
在 Spring Batch 3.0 中引入的 Job
范围在配置方面类似于 Step
范围,但它是 Job
上下文的范围,因此每个正在运行的作业只有一个此类 bean 的实例。此外,还提供了对可从 JobContext
访问的引用的延迟绑定的支持,方法是使用 #{..}
占位符。使用此功能,您可以从作业或作业执行上下文以及作业参数中提取 bean 属性。
-
Java
-
XML
以下示例显示了在 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))
...
}
以下示例显示了在 XML 中绑定到作业范围的示例。
<bean id="..." class="..." scope="job">
<property name="name" value="#{jobParameters[input]}" />
</bean>
<bean id="..." class="..." scope="job">
<property name="name" value="#{jobExecutionContext['input.name']}.txt" />
</bean>
因为它默认不是 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 正确创建实现此接口的代理,从而通过按预期调用 open
、update
和 close
方法来遵守其契约。
建议使此类 bean 的 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();
}