Job
和 Step
属性的后期绑定
Job
and Step
Attributes
前面展示的 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 不应是步骤作用域或作业作用域。如果在步骤定义中需要晚期绑定,则该步骤的组件(任务片段、项读取器/写入器、完成策略等)应该是被作用域限定的部分。
如果你使用的是 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
作用域是实现 late binding 的必要条件,因为该 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" />
工作范围
Job
作用域在 Spring Batch 3.0 中被引入,它与配置中的 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 配置风格定义作用域为 job 或 step 的 ItemStream
bean 时,bean 定义方法的返回类型至少应为 ItemStream
。这是必需的,以便 Spring Batch 正确创建实现该接口的代理,并因此按照预期调用 open
、update
和 close
方法以遵守其契约。
建议将此类 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();
}