`Job` 和 `Step` 屬性的後期繫結

前面展示的 XML 和平面檔案示例都使用了 Spring 的 `Resource` 抽象來獲取檔案。這是因為 `Resource` 有一個返回 `java.io.File` 的 `getFile` 方法。你可以使用標準的 Spring 結構來配置 XML 和平面檔案資源

  • Java

  • XML

以下示例展示了 Java 中的後期繫結

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

以下示例展示了 XML 中的後期繫結

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 中從屬性讀取檔名

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

以下示例展示瞭如何在 XML 中從屬性讀取檔名

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 中引數化檔名

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

以下示例展示瞭如何在 XML 中引數化檔名

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`

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

以下示例展示瞭如何在 XML 中訪問 `ExecutionContext`

XML 配置
<bean id="flatFileItemReader" scope="step"
      class="org.springframework.batch.item.file.FlatFileItemReader">
    <property name="resource" value="#{jobExecutionContext['input.file.name']}" />
</bean>
XML 配置
<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 範圍的示例

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

以下示例展示了在 XML 中繫結到 Step 範圍的示例

XML 配置
<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 範圍的示例

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

以下示例展示了在 XML 中繫結到 Job 範圍的示例

XML 配置
<bean id="..." class="..." scope="job">
    <property name="name" value="#{jobParameters[input]}" />
</bean>
XML 配置
<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 定義方法返回最具體的已知實現,如下例所示

使用最具體的返回型別定義一個 Step 範圍的 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();
}