在 SpringSource Application Platform 中執行 Spring Batch 作業

工程 | Dave Syer | 2008年5月30日 | ...

在本文中,我將向您展示如何在 SpringSource Application Platform 中執行 Spring Batch 作業。我之前為 JavaOne 做了一個小演示,然後在倫敦 Spring 使用者組再次進行了演示,我認為分享一下會很有用。示例程式碼 在此處

Bundle(捆綁包)

首先,我們將快速瀏覽一下示例程式碼中的 Bundle。現在,或者在安裝了一些 Bundle 之後,隨時啟動伺服器。

Bundle: hsql-server

這個 Bundle 對於開發和測試很有用。它所做的只是以伺服器模式啟動一個 HSQLDB 例項,這樣您就可以連線到它並使用 SQL 語句檢查資料庫。您只需將其拖放到 Servers View 中的 Platform Server 例項中即可。請先執行此操作,因為 Platform 會記住安裝 Bundle 的順序,並按該順序啟動它們。必須先啟動此 Bundle,因為其他 Bundle 將嘗試連線到資料庫伺服器。

Bundle 的配置位於META-INF/spring/module-context.xml(這對於 Platform Bundle 是約定俗成的)- Spring DM 會從以下位置拾取所有 XML 檔案META-INF/spring。此 Bundle 僅使用 Spring 來配置和啟動 HSQL 伺服器的例項。

有一個整合測試可用於檢查配置。

Eclipse 專案還包含一個用於 HSQL Swing 客戶端的啟動配置,因此您可以在 GUI 中檢視資料庫內容。啟動它,並使用同一專案中的META-INF/batch-hsql.properties中提供的屬性連線到伺服器例項(url=jdbc:hsqldb:hsql://:9005/samples)。

Bundle: data-source

此 Bundle 是一個配置 Bundle,它公開一個用於javx.sql.DataSource的 OSGi 服務。接下來將其放入伺服器。有一個簡單的整合測試可用於檢查配置 - 它只是獲取一個數據源連線並斷言它不為 null。

Bundle: data-source-initializer

這是在測試環境中另一個方便的 Bundle。它的作用是拆除資料庫並重新安裝其餘 Bundle 所需的表(批處理元資料和作業本身的某些業務表)。當您將此 Bundle 安裝到伺服器時,它將新增表,這些表隨後應出現在 HSQL Swing GUI 中。一旦安裝完成,您就可以將其移除(在 Server View 中右鍵單擊 Bundle,然後選擇 Remove)。

Bundle: job-launcher

這是第一個包含 Spring Batch 依賴項的 Bundle。它主要是一個配置 Bundle,為將實際執行作業的其他 Bundle 公開服務(JobLauncher、JobRepository、TransactionManager)。安裝後,它就可以在此處提供服務。

Bundle 的配置位於META-INF/spring/module-context.xml照常。這是 Spring Batch 示例中simple-job-launcher-context.xml的一個精簡版本。它只需要定義將匯出的 Bean,即

<bean id="jobLauncher"
    class="org.springframework.batch.core.launch.support.SimpleJobLauncher">
  <property name="jobRepository" ref="jobRepository" />
</bean>

<bean id="jobRepository"
    class="org.springframework.batch.core.repository.support.JobRepositoryFactoryBean">
  <property name="dataSource" ref="dataSource" />
  <property name="databaseType" value="hsql" />
</bean>
	
<bean id="transactionManager" 
    class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
  <property name="dataSource" ref="dataSource"/>
</bean>

唯一其他的配置是針對JobRepository的事務建議(在 Spring Batch 1.1 中不需要)。dataSource 引用來自上面data-sourceBundle 公開的 OSGi 服務。要了解該引用如何匯入以及本地服務如何公開到 OSGi Service Registry,我們可以檢視META-INF/spring/osgi-context.xml:

<reference id="dataSource" interface="javax.sql.DataSource" />

<service ref="jobLauncher"
  interface="org.springframework.batch.core.launch.JobLauncher" />
<service ref="jobRepository"
  interface="org.springframework.batch.core.repository.JobRepository" />
<service ref="transactionManager"
  interface="org.springframework.transaction.PlatformTransactionManager" />

這是 Spring DM 的一個相當直接的用法。重要的是模組上下文與特定於 OSGi 的上下文是分開的。這允許我們為模組上下文編寫整合測試,而無需部署到 Platform。因此,我們有

@ContextConfiguration
@RunWith(SpringJUnit4ClassRunner.class)
public class JobLauncherIntegrationTests {

  @Autowired
  private JobLauncher jobLauncher;

  @Test
  public void testLaunchJob() throws Exception {
    assertNotNull(jobLauncher);
  }

}

測試載入上下文,新增本地資料來源定義以替換 OSGi 資料來源(參見JobLauncherIntegrationTests-context.xml),然後斷言作業啟動器可用。您可以像往常一樣直接從 Eclipse 執行測試。

SimpleJobLauncherBean

除了上面公開 OSGi 容器中服務的配置之外,此 Bundle 還匯出一個包。檢視MANIFEST.MF:
...
Export-Package: com.springsource.consulting.batch.support
...

如果您檢視此包,您會找到一個便捷類,其他 Bundle 可以使用它來啟動作業(SimpleJobLauncherBean)。SimpleJobLauncherBean是一個ApplicationListener,這意味著包含其中一個的任何 SpringApplicationContext都會嘗試在啟動時(上下文載入時)啟動作業。它的工作方式是監聽ContextRefreshedEvent,然後嘗試啟動作業。

try {
  jobLauncher.run(job, converter.getJobParameters(parameters));
} catch (JobExecutionAlreadyRunningException e) {
  logger.error("This job is already running", e);
} catch (JobInstanceAlreadyCompleteException e) {
  logger.info("This job is already complete.  "
    + "Maybe you need to change the input parameters?", e);
} catch (JobRestartException e) {
  logger.error("Unspecified restart exception", e);
}

啟動作業的計劃是為每個作業建立一個 Bundle,並讓它定義其中一個SimpleJobLauncherBean例項。

Bundle: hello-world

這是一個非常簡單的作業 Bundle。它具有大型作業的所有功能(從檔案輸入到資料庫輸出),但使用非常簡單的域模型和非常小的資料集。

將 Bundle 放入正在執行的伺服器例項中。它啟動得很快,由於作業範圍很小,您將立即在批處理元資料中看到效果。在 HSQL Swing GUI 中,您可以執行一些 SQL,例如

SELECT * FROM BATCH_STEP_EXECUTION

並檢視結果,類似這樣

STEP_EXECUTION_IDVERSIONSTEP_NAME...STATUS...
04helloWorldStep...COMPLETED...

這表明作業已執行(併成功完成)。步驟的配置位於META-INF/spring/module-context.xml:

<bean
	class="com.springsource.consulting.batch.support.SimpleJobLauncherBean">
	<constructor-arg ref="jobLauncher" />
	<constructor-arg ref="helloWorld" />
	<property name="parameters" value="launch.timestamp=${launch.timestamp}"/>
</bean>

<bean id="helloWorld" parent="simpleJob">
	<property name="steps">
		<bean parent="simpleStep" id="helloWorldStep">
			<property name="commitInterval" value="100" />
			<property name="itemReader">
    ...
			</property>
			<property name="itemWriter">
    ...
			</property>
		</bean>
	</property>
</bean>

從上面可以看到,我們有一個常規的 Spring Batch 作業配置(稱為“helloWorld”),帶有一個步驟。步驟 ID(“helloWorldStep”)已在上面的資料庫查詢中看到,表明該步驟已執行(一次)。所有步驟所做的就是從平面檔案讀取資料,將行轉換為域物件,然後將它們寫入 stdout。您可以透過檢查 Platform 主目錄中的跟蹤日誌來檢視結果,例如,如果您tail -f serviceability/trace/trace.log | grep -i hello您應該會看到

[2008-05-30 15:57:04.140] platform-dm-11              
  com.springsource.consulting.batch.hello.MessageWriter.unknown 
  I Message: [Hello World]
[2008-05-30 15:57:04.140] platform-dm-11              
  com.springsource.consulting.batch.hello.MessageWriter.unknown 
  I Message: [Hello Small World]

如果您願意,可以透過編輯 Bundle 中的檔案之一(例如 MANIFEST 或一個 Spring 配置檔案)並儲存它來再次執行該作業。工具會拾取更改並重新部署 Bundle。此作業的設定方式是,它會使用新的一組引數(使用時間戳)開始每次執行,因此它應該總是成功執行。

作業結束

一旦作業完成(無論成功還是失敗),我們就希望將系統保持在指示發生情況的狀態。對此有許多可能的處理方法,但我們真正需要的是一種可工具化的方法,以便可以通知操作員,並採取任何必要的行動(例如重新啟動失敗的作業或為成功的作業重新引數化以用於下次執行)。操作員可以是人類,也可以是系統功能。

為了標記作業的結束,SimpleJobLauncherBean直接抓取封閉的 OSGiBundle例項,並停止它。這是一個相當簡單的模型,但它具有 API 定義良好且得到 OSGi 平臺普遍支援的好處。原則上,只要容器(SpringSource Application Platform)可以捕獲這些 Bundle 事件,它就可以非常靈活地擴充套件。這些是我們可能會在 Platform 2.0 版本中看到的 Batch Personality 功能。如果您對行為和操作員所需的功能有任何想法,請透過評論本文來幫助我們。

我們可以透過登入 Equinox 控制檯來驗證作業 Bundle 的狀態。如果您轉到命令列並鍵入telnet localhost 2401您應該會看到 Platform 的命令提示符。

osgi>

鍵入“ss”並按 Enter 鍵,您將看到已安裝的 Bundle 列表。

osgi> ss

Framework is launched.

id      State       Bundle
...
86      RESOLVED    org.springframework.batch.infrastructure_1.0.0
87      RESOLVED    org.springframework.batch.core_1.0.0
88      RESOLVED    com.springsource.org.apache.commons.lang_2.4.0
97      ACTIVE      job.launcher_1.0.0
99      RESOLVED    hello.world_1.0.0

osgi>

因此,ID 為 97 的 Bundle 是作業啟動器,並且它是活動的。ID 為 99 的 Bundle 是 hello world 作業(您的 ID 可能不同),它已解析,但由於在作業執行完成時已停止,因此未啟用。

您可以從 OSGi 命令列重新啟動作業

osgi> start 99

osgi> ss

Framework is launched.

id      State       Bundle
...
86      RESOLVED    org.springframework.batch.infrastructure_1.0.0
87      RESOLVED    org.springframework.batch.core_1.0.0
88      RESOLVED    com.springsource.org.apache.commons.lang_2.4.0
97      ACTIVE      job.launcher_1.0.0
99      RESOLVED    hello.world_1.0.0

osgi>

作業 Bundle 已恢復到已解析狀態,但它已再次執行了作業,您可以從 HSQL GUI 或如前所述從跟蹤日誌中進行驗證。

STEP_EXECUTION_IDVERSIONSTEP_NAME...STATUS...
04helloWorldStep...COMPLETED...
14helloWorldStep...COMPLETED...
24helloWorldStep...COMPLETED...

作業的輸入檔案

Hello world 有一個固定在 Bundle 中的輸入檔案。有時這並不合適,在實踐中,您很可能會在檔案系統上找到輸入檔案。另一方面,基於熱部署 Bundle 的部署模型,也許將輸入檔案與作業執行一起打包並不是一個壞主意 - Bundle 的佔用空間可以非常小,並且它包含了一個完美的審計記錄,記錄了確切執行的內容。歡迎發表評論。

Bundle: football-job

示例程式碼中還有一個作業 Bundle,它是一個更真實的業務應用程式(它是 Spring Batch 的足球作業示例)。您可以以與 hello-world 作業相同的方式啟動和重新啟動它。

如果您剛剛嘗試過,您可能會發現第二次及後續啟動時,資料庫中沒有任何變化。這是預期的,因為您重新啟動了一個成功完成的作業例項,所以它不會再次處理資料。事實上,一個異常是由JobLauncher丟擲的,被SimpleJobLauncherBean捕獲並記錄(因此它會出現在跟蹤日誌中)。

設定工作區

SpringSource Application Platform

如果您以某種方式錯過了釋出公告,或者還沒有時間嘗試(也許您認為它只與 Web 應用程式有關),這裡有一些連結可以幫助您入門

先決條件

要遵循示例並執行示例程式碼,您將需要以下部分或全部內容。我使用了所有這些,因此使用它們可能會獲得最順暢的體驗。

安裝 SpringSource Eclipse 工具後,您需要建立一個伺服器例項。轉到 File->New->Other... 並找到 Server->Server。選擇 SpringSource 和下面的伺服器型別,然後使用瀏覽對話方塊查詢 Platform 安裝。

下載依賴項

我們都在熱切地等待 SpringSource Eclipse 工具提供自動下載和安裝依賴項的功能。如果您閱讀本文時該功能尚不可用,那麼您可以按照我的方法進行,如果您願意的話。以下是我所做的
  • (可選)從一個空的本地 Maven 儲存庫開始(刪除 ~/.m2/repository,或在 settings.xml 中指向一個新位置)
  • 在首次安裝 Bundle 之前,開啟專案的 pom.xml 並找到具有 id “shell”的元素。
  • 將 activeByDefault 標誌更改為 true,然後等待 Q4E 下載依賴項。
  • 使用 Q4E 視覺化工具檢查依賴項(右鍵單擊專案並選擇 Maven2->Analyse Dependencies(或 Visualize Dependencies)。您只需執行此操作即可檢視傳遞依賴項。(您也可以在命令列上使用$ mvn dependency:tree)。
  • 此時,我總是右鍵單擊專案並選擇 Maven2->Fetch Source JARs。這是可選的,但可以簡化開發並進行除錯。
  • 將直接依賴項複製到 Platformbundles/usr目錄。嚴格來說,您只需要複製那些尚未在bundles/ext中的。在命令列(使用合適的作業系統)中,您可以執行
    $ find ~/.m2/repository -name \*.jar -exec cp {} bundles/usr \;
    
  • 您可能需要對 Bundle 專案中的部分或全部MANIFEST.MF檔案進行“虛假編輯”以強制工具重新整理。
  • 將 activeByDefault 標誌切換回 false。

無需重啟 Eclipse 或其他任何操作。“Bundle Dependencies”類路徑容器應包含您剛剛下載的執行時依賴項。當 Problems 檢視中的所有 Eclipse 錯誤(紅色的邊距標記)都消失後,我們就準備好了。

我非常樂意聽到人們有一個更好的方法來做到這一點。其他人已經發展了其他方法,但對我來說似乎都不太方便。實際上,編寫一個命令列 Maven 目標很容易,但我還沒有見過那個。

Beta5 更新

使用 beta5,您不需要“查詢和複製”步驟,因為 platform.config 允許您將本地 Maven 儲存庫指向作為依賴項源,而不是 bundles/usr。

原則上,您也完全不需要執行時依賴項的 Maven 本地儲存庫。您可以開啟 Platform 執行時(在 Servers 檢視中右鍵單擊並選擇 Open),然後直接瀏覽並下載依賴項到bundles/usr。目前唯一的缺點是(工具團隊正在努力改進它),它沒有提供任何傳遞依賴項的檢視 - 您必須明確知道需要哪些 Bundle。對於本部落格的示例,這很容易,因為 MANIFESTs 都已完全指定了依賴項。當您不確定它們是什麼並且必須從頭開始建立 MANIFEST 時,情況就更糟了。為此,我目前仍在使用 Q4E。

結束

磨刀不誤砍柴工,Platform 是一個非常豐富的環境,所以您可以確定我在這裡展示的並不是在 Platform 中執行作業的唯一方法。希望它是一個好的起點。

Application Platform 1.0 釋出的大部分重點都在 Web 層,雖然這顯然是必不可少的(並且非常棘手),但還有其他事情需要處理。2.0 版本將具有特定的批處理相關功能(Batch Personality),因此我們現在所做的一切都將有助於充實該版本的關鍵功能需求。因此,如果您有機會嘗試一下,並有一些建設性的意見,特別是關於操作方面的,當我們開始構建 Batch Personality 時,它們將非常有用。

獲取 Spring 新聞通訊

透過 Spring 新聞通訊保持聯絡

訂閱

領先一步

VMware 提供培訓和認證,助您加速進步。

瞭解更多

獲得支援

Tanzu Spring 提供 OpenJDK™、Spring 和 Apache Tomcat® 的支援和二進位制檔案,只需一份簡單的訂閱。

瞭解更多

即將舉行的活動

檢視 Spring 社群所有即將舉行的活動。

檢視所有