Late Binding of Job and Step Attributes

前面显示的 XML 和平面文件示例都使用 Spring Resource 抽象来获取文件。这有效,因为 Resource 有一个 getFile 方法,它返回一个 java.io.File。您可以使用标准 Spring 结构配置 XML 和平面文件资源:

Both the XML and flat file examples shown earlier use the Spring Resource abstraction to obtain a file. This works because Resource has a getFile method that returns a java.io.File. You can configure both XML and flat file resources by using standard Spring constructs:

Java

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

The following example shows late binding in Java:

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

以下示例显示 XML 中的延迟绑定:

The following example shows late binding in XML:

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

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

The preceding Resource loads the file from the specified file system location. Note that absolute locations have to start with a double slash (//). In most Spring applications, this solution is good enough, because the names of these resources are known at compile time. However, in batch scenarios, the file name may need to be determined at runtime as a parameter to the job. This can be solved using -D parameters to read a system property.

Java

以下是显示如何从 Java 中的属性读取文件的示例:

The following shows how to read a file name from a property in Java:

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

以下示例显示如何从 XML 中的属性读取文件名称:

The following example shows how to read a file name from a property in XML:

XML Configuration
<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")。

All that would be required for this solution to work would be a system argument (such as -Dinput.file.name="file://outputs/file.txt").

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

Although you can use a PropertyPlaceholderConfigurer here, it is not necessary if the system property is always set because the ResourceEditor in Spring already filters and does placeholder replacement on system properties.

通常,在批量设置中,最好在作业的 JobParameters 中参数化文件名(而不是通过系统属性),然后再访问这些参数。为了完成此操作,Spring Batch 允许延迟绑定各种 JobStep 属性。

Often, in a batch setting, it is preferable to parameterize the file name in the JobParameters of the job (instead of through system properties) and access them that way. To accomplish this, Spring Batch allows for the late binding of various Job and Step attributes.

Java

以下示例显示如何用 Java 参数化文件名:

The following example shows how to parameterize a file name in Java:

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

以下示例显示如何在 XML 中参数化文件名:

The following example shows how to parameterize a file name in XML:

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

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

You can access both the JobExecution and StepExecution level ExecutionContext in the same way.

Java

以下示例显示如何用 Java 访问 ExecutionContext

The following example shows how to access the ExecutionContext in Java:

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

以下示例显示如何在 XML 中访问 ExecutionContext

The following example shows how to access the ExecutionContext in XML:

XML Configuration
<bean id="flatFileItemReader" scope="step"
      class="org.springframework.batch.item.file.FlatFileItemReader">
    <property name="resource" value="#{jobExecutionContext['input.file.name']}" />
</bean>
XML Configuration
<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 Scope。 `Step`Bean 不应为 step 范围。如果 step 定义中需要后期绑定,则该 step 的组件(任务项、项读取器或写入器等)应改为范围约束。

Any bean that uses late binding must be declared with scope="step". See Step Scope for more information. A Step bean should not be step-scoped. If late binding is needed in a step definition, the components of that step (tasklet, item reader or writer, and so on) are the ones that should be scoped instead.

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

If you use Spring 3.0 (or above), the expressions in step-scoped beans are in the Spring Expression Language, a powerful general purpose language with many interesting features. To provide backward compatibility, if Spring Batch detects the presence of older versions of Spring, it uses a native expression language that is less powerful and that has slightly different parsing rules. The main difference is that the map keys in the example above do not need to be quoted with Spring 2.5, but the quotes are mandatory in Spring 3.0.

Step Scope

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

All of the late binding examples shown earlier have a scope of step declared on the bean definition.

Java

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

The following example shows an example of binding to step scope in Java:

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

以下示例显示了 XML 中绑定到 step 作用域的示例:

The following example shows an example of binding to step scope in XML:

XML Configuration
<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 容器的一部分,因此必须采用以下方式显式添加这个 scope:使用 batch 命名空间,明确地包含 StepScope 的 bean 定义,或使用 @EnableBatchProcessing 注释。仅使用其中一种方法。以下示例使用 batch 命名空间:

Using a scope of Step is required to use late binding, because the bean cannot actually be instantiated until the Step starts, to let the attributes be found. Because it is not part of the Spring container by default, the scope must be added explicitly, by using the batch namespace, by including a bean definition explicitly for the StepScope, or by using the @EnableBatchProcessing annotation. Use only one of those methods. The following example uses the batch namespace:

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

The following example includes the bean definition explicitly:

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

Job Scope

自 Spring Batch 3.0 引入以来,Job scope 配置与 Step scope 类似,但它是 Job context 的一个 scope,因此每运行一个作业,此类 bean 只有一个实例。此外,还支持通过 #{..} 占位符延迟绑定可以从 JobContext 访问的引用。通过该特性,你可以从 Job 或 Job 执行 context 以及 Job 参数中提取 bean 属性。

Job scope, introduced in Spring Batch 3.0, is similar to Step scope in configuration but is a scope for the Job context, so that there is only one instance of such a bean per running job. Additionally, support is provided for late binding of references accessible from the JobContext by using #{..} placeholders. Using this feature, you can pull bean properties from the job or job execution context and the job parameters.

Java

以下示例展示在 Java 中绑定到 Job scope 的示例:

The following example shows an example of binding to job scope in Java:

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

以下示例展示在 XML 中绑定到 Job scope 的示例:

The following example shows an example of binding to job scope in XML:

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

由于缺省情况下它不是 Spring 容器的一部分,因此必须通过以下方式显式添加该 scope:使用 batch 命名空间,明确包含 JobScope 的 bean 定义,或使用 @EnableBatchProcessing 注释(仅选择一种方法)。以下示例使用 batch 命名空间:

Because it is not part of the Spring container by default, the scope must be added explicitly, by using the batch namespace, by including a bean definition explicitly for the JobScope, or by using the @EnableBatchProcessing annotation (choose only one approach). The following example uses the batch namespace:

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

The following example includes a bean that explicitly defines the JobScope:

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

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

There are some practical limitations of using job-scoped beans in multi-threaded or partitioned steps. Spring Batch does not control the threads spawned in these use cases, so it is not possible to set them up correctly to use such beans. Hence, we do not recommend using job-scoped beans in multi-threaded or partitioned steps.

Scoping ItemStream components

使用 Java 配置方式来定义作业或步骤作用域的 ItemStream Bean 时,Bean 定义方法的返回类型至少应该是 ItemStream。这是必需的,以便 Spring Batch 正确创建实现此接口的代理,并因此通过按预期调用 openupdateclose 方法来履行其契约。

When using the Java configuration style to define job or step scoped ItemStream beans, the return type of the bean definition method should be at least ItemStream. This is required so that Spring Batch correctly creates a proxy that implements this interface, and therefore honors its contract by calling open, update and close methods as expected.

建议让此类 Bean 的 Bean 定义方法返回最明确已知实现,如下例所示:

It is recommended to make the bean definition method of such beans return the most specific known implementation, as shown in the following example:

Define a step-scoped bean with the most specific return type
@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();
}