`Job` 和 `Step` 属性的后期绑定
前面展示的 XML 和平面文件示例都使用了 Spring 的 `Resource` 抽象来获取文件。这是因为 `Resource` 有一个返回 `java.io.File` 的 `getFile` 方法。你可以使用标准的 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 应用中,这个解决方案已经足够好,因为这些资源的名称在编译时是已知的。然而,在批处理场景中,文件名可能需要在运行时作为 Job 的参数来确定。这可以通过使用 `-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` 已经过滤并对系统属性进行了占位符替换。 |
通常,在批处理设置中,更可取的方式是将文件名在 Job 的 `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 范围。`Step` bean 不应该具有 step 或 job 范围。如果 step 定义中需要后期绑定,则该 step 的组件(tasklet、item reader/writer、完成策略等)应改为指定范围。 |
如果你使用 Spring 3.0(或更高版本),step 范围内的 bean 中的表达式是 Spring Expression Language,这是一个功能强大且有许多有趣特性的通用语言。为了提供向后兼容性,如果 Spring Batch 检测到存在旧版本的 Spring,它会使用一种功能较弱且解析规则略有不同的原生表达式语言。主要区别在于,在 Spring 2.5 中,上面示例中的 map 键不需要加引号,但在 Spring 3.0 中,引号是强制性的。 |
Step 范围
前面展示的所有后期绑定示例都在 bean 定义上声明了 `step` 范围。
-
Java
-
XML
以下示例展示了在 Java 中绑定到 Step 范围的示例
@StepScope
@Bean
public FlatFileItemReader flatFileItemReader(@Value("#{jobParameters[input.file.name]}") String name) {
return new FlatFileItemReaderBuilder<Foo>()
.name("flatFileItemReader")
.resource(new FileSystemResource(name))
...
}
以下示例展示了在 XML 中绑定到 Step 范围的示例
<bean id="flatFileItemReader" scope="step"
class="org.springframework.batch.item.file.FlatFileItemReader">
<property name="resource" value="#{jobParameters[input.file.name]}" />
</bean>
使用 `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 中引入的 `Job` 范围在配置上类似于 `Step` 范围,但它是针对 `Job` 上下文的范围,因此每个运行的 Job 只有一个此类 bean 实例。此外,通过使用 `#{..}` 占位符,提供了对从 `JobContext` 可访问的引用的后期绑定支持。使用此功能,你可以从 Job 或 Job 执行上下文以及 Job 参数中提取 bean 属性。
-
Java
-
XML
以下示例展示了在 Java 中绑定到 Job 范围的示例
@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 中绑定到 Job 范围的示例
<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" />
在多线程或分区 Step 中使用 Job 范围的 bean 存在一些实际限制。Spring Batch 不控制这些用例中产生的线程,因此无法正确设置它们来使用此类 bean。因此,我们不建议在多线程或分区 Step 中使用 Job 范围的 bean。 |
为 `ItemStream` 组件设置范围
使用 Java 配置方式定义 Job 或 Step 范围的 `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();
}