JobStep 屬性的延遲綁定

先前顯示的 XML 和平面檔案範例都使用 Spring Resource 抽象概念來取得檔案。這之所以有效,是因為 Resource 有一個 getFile 方法,該方法會傳回 java.io.File。您可以使用標準 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 允許各種 JobStep 屬性的延遲綁定。

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

您可以透過相同的方式存取 JobExecutionStepExecution 層級的 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 ScopeStep bean 不應是 step-scoped。如果在 step 定義中需要延遲綁定,則該 step 的元件 (tasklet、item reader 或 writer 等) 才是應該被 scoped 的元件。
如果您使用 Spring 3.0 (或更高版本),step-scoped bean 中的表達式採用 Spring Expression Language,這是一種功能強大的通用語言,具有許多有趣的功能。為了提供向下相容性,如果 Spring Batch 偵測到較舊版本的 Spring,它會使用功能較弱且解析規則略有不同的原生表達式語言。主要差異在於,在上面的範例中,Spring 2.5 中地圖索引鍵不需要用引號括起來,但在 Spring 3.0 中引號是強制性的。

Step Scope

先前顯示的所有延遲綁定範例都在 bean 定義上宣告了 step 的 scope。

  • Java

  • XML

以下範例顯示 Java 中綁定到 step scope 的範例

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 scope 的範例

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

使用 Step 的 scope 是使用延遲綁定所必需的,因為 bean 實際上無法在 Step 啟動之前實例化,以讓屬性被找到。因為它預設不是 Spring 容器的一部分,所以 scope 必須明確添加,方法是使用 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 Scope

Job scope 是在 Spring Batch 3.0 中引入的,在設定上與 Step scope 類似,但它是 Job 上下文的 scope,因此每個正在執行的 Job 只有一個此類 bean 的實例。此外,透過使用 #{..} 佔位符,為可從 JobContext 存取的參考提供了延遲綁定的支援。使用此功能,您可以從 job 或 job 執行上下文和 job 參數中提取 bean 屬性。

  • Java

  • XML

以下範例顯示 Java 中綁定到 job scope 的範例

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 scope 的範例

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 容器的一部分,所以 scope 必須明確添加,方法是使用 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-scoped bean 存在一些實際限制。Spring Batch 不控制在這些用例中產生的執行緒,因此無法正確設定它們以使用此類 bean。因此,我們不建議在多執行緒或分割 step 中使用 job-scoped bean。

Scoping ItemStream 元件

當使用 Java 設定樣式來定義 job 或 step scoped ItemStream bean 時,bean 定義方法的返回類型應至少為 ItemStream。這是必需的,以便 Spring Batch 正確建立實作此介面的代理,因此透過在預期時呼叫 openupdateclose 方法來遵守其合約。

建議使此類 bean 的 bean 定義方法傳回最特定的已知實作,如下列範例所示

使用最特定的返回類型定義 step-scoped 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();
}