在 SpringSource 應用平台中執行 Spring Batch Job

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

在本文中,我將向您展示如何在 SpringSource 應用平台中執行 Spring Batch job。我運行了一個早期版本,作為 JavaOne 的一個小演示,然後又在倫敦 Spring User Group 中運行,並認為分享它可能是一件好事。 範例程式碼在這裡

套件 (Bundles)

首先,我們快速瀏覽一下範例程式碼中的套件。 現在啟動伺服器,或在您安裝了一些套件後的任何時間點啟動。

套件: hsql-server

這個對於開發和測試非常有用。 它所做的只是在伺服器模式下啟動一個 HSQLDB 實例,以便您可以使用 SQL 語句連接到它並檢查資料庫。 您可以將它拖放到 Servers View 中的 Platform Server 實例中。 首先執行此操作,因為 Platform 會記住套件的安裝順序,並按該順序啟動它們。 必須先啟動這個,因為其他套件會嘗試連接到資料庫伺服器。

套件組態位於META-INF/spring/module-context.xml(這是 Platform 套件的慣例) - Spring DM 會從META-INF/spring中提取所有 XML 檔案。 這個只是使用 Spring 來配置和啟動 HSQL Server 的一個實例。

有一個整合測試可用於檢查組態。

Eclipse 專案還包含 HSQL Swing 客戶端的啟動組態,因此您可以在 GUI 中看到資料庫內容。 啟動它並使用以下屬性連接到伺服器實例META-INF/batch-hsql.properties在同一個專案中 (url=jdbc:hsqldb:hsql://localhost:9005/samples)。

套件: data-source

此套件是一個配置套件,它為javx.sql.DataSource公開一個單一的 OSGi 服務。 將其拖放到伺服器中。 有一個簡單的整合測試可用於檢查配置 - 它只是從資料來源取得一個連接並斷言它不是 null。

套件: data-source-initializer

這是另一個方便的套件,可用於測試環境。 它的工作是拆除資料庫並重新安裝其餘套件所需的表(批次元資料,以及 job 本身的一些業務表)。 將此套件安裝到伺服器中時,它將添加表,然後這些表應顯示在 HSQL Swing GUI 中。 安裝一次後,您可以將其刪除(在 Server View 中右鍵點擊該套件,然後選擇 Remove)。

套件: job-launcher

這是第一個包含一些 Spring Batch 依賴項的套件。 它主要是一個配置套件,為實際運行 job 的其他套件公開服務(JobLauncher、JobRepository、TransactionManager)。 安裝後,它就可以放在那裡提供服務。

套件組態位於META-INF/spring/module-context.xml一如既往。 它是simple-job-launcher-context.xml的精簡版本,來自 Spring Batch 範例。 它只需要定義要匯出的 beans,即

<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-source套件以上公開的 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),然後斷言 job launcher 可用。 您可以直接從 Eclipse 以正常方式執行測試。

TheSimpleJobLauncherBean

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

如果您查看此套件,您會發現一個方便的類,其他套件可以使用它來啟動 job (SimpleJobLauncherBean)。 TheSimpleJobLauncherBeanis anApplicationListener這意味著任何 SpringApplicationContext包含其中一個的都將嘗試在啟動時(載入上下文時)啟動 job。 它通過監聽ContextRefreshedEvent然後嘗試啟動 job

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);
}

啟動 job 的計畫是簡單地為每個 job 建立一個套件,並讓它定義其中一個SimpleJobLauncherBean實例。

套件: hello-world

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

將套件放入運行的伺服器實例中。 它啟動速度非常快,並且由於 job 的範圍很小,您將立即在批次元資料中看到效果。 在 HSQL Swing GUI 中,您可以執行一些 SQL,例如

SELECT * FROM BATCH_STEP_EXECUTION

並查看結果,如下所示

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

這表示 job 已執行(並成功完成)。 步驟的組態位於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 job 組態(稱為 "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]

如果您願意,您可以再次運行 job,只需編輯套件中的一個檔案(例如 MANIFEST 或其中一個 Spring 配置檔案)並保存即可。 這些工具會獲取更改並重新部署套件。 由於此 job 的設定方式,它會使用一組新的參數(使用時間戳記)啟動每次執行,因此它應該始終成功運行。

Job 的結束

一旦 job 完成,無論是成功還是失敗,我們都希望將系統置於一個表示已發生的狀態。 有很多可能的方法可以做到這一點,但我們真正需要的只是一種可工具化的方法,以便可以通知操作員,並採取必要的任何措施(例如重新啟動失敗的 job 或重新參數化成功的 job 以供下次運行)。 操作員可能是人,也可能是系統功能。

為了表示 job 的結束,SimpleJobLauncherBean只是獲取封閉的 OSGiBundle實例,然後停止它。 這是一個非常簡單的模型,但具有以下優點:API 已明確定義並受到 OSGi 平台普遍支持。 原則上,只要容器 (SpringSource 應用平台) 可以捕獲這些套件事件,它就可以非常靈活地擴展。 這些是我們可能會在 Platform 2.0 版的 Batch 個性化中看到的功能。 如果您對行為應該是什麼以及操作員需要哪些功能有任何想法,請通過評論本文來幫助我們。

我們可以通過登錄 Equinox 控制台來驗證 job 套件的狀態。 如果您轉到命令行並輸入telnet localhost 2401您應該會看到平台上的命令提示符

osgi>

輸入 "ss" 並點擊返回,您將看到已安裝套件的列表

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 的套件是 job launcher,它是活動的。 id=99 的套件是 hello world job(在您的情況下,id 可能不同),它是已解析的,但由於 job 完成執行時已停止,因此它不是活動的。

您可以從 OSGi 命令行再次重新啟動 job

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>

job 套件恢復到已解析狀態,但它再次執行了 job,您可以像以前一樣從 HSQL GUI 或從追蹤日誌進行驗證。

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

Jobs 的輸入檔案

Hello world 有一個固定輸入檔案,打包在套件中。 有時這可能不合適,並且在實踐中常見的是找到位於檔案系統上的輸入檔案。 另一方面,對於基於熱部署套件的部署模型,也許將輸入檔案與 job 執行一起打包並不是一個壞主意 - 套件的佔用空間可能非常小,並且它包含精確執行的內容的完美稽核記錄。 評論會很有趣。

套件: football-job

範例程式碼中還有另一個 job 套件,它是一個更現實的業務應用程式(它是 Spring Batch 中的 football job 範例)。 您可以像啟動 hello-world job 一樣啟動它並重新啟動它。

如果你剛才試過這樣做,你可能會發現,在第二次及後續的啟動中,資料庫沒有任何變化。這是預期的,因為你重新啟動了一個成功完成的 Job 實例,所以它不會再次處理資料。實際上,JobLauncher拋出了一個例外,並且被SimpleJobLauncherBean捕獲並記錄下來(所以它會顯示在追蹤日誌中)。

設定工作區

SpringSource 應用程式平台

如果你不知何故錯過了發布公告,或者還沒有時間嘗試它(也許你認為它只與網路應用程式有關),這裡有一些連結可以幫助你入門

先決條件

要遵循這些範例並執行範例程式碼,你需要以下部分或全部。 我使用了所有這些,因此最順暢的體驗可能來自於使用它們全部。

安裝 SpringSource Eclipse 工具後,你需要建立一個伺服器實例。轉到檔案->新增->其他... 並找到伺服器->伺服器。選擇 SpringSource 和下面的伺服器類型,然後使用瀏覽對話方塊找到平台安裝目錄。

下載相依性

我們都在滿懷期待地等待 SpringSource Eclipse 工具提供相依性的自動下載和安裝。 如果在你閱讀本文時該功能還不可用,那麼你可以像我一樣做,如果你願意的話。 以下是我所做的
  • (可選)從一個空的本地 Maven 儲存庫開始(刪除 ~/.m2/repository,或在 settings.xml 中指向一個新的位置)
  • 在第一次安裝套件之前,打開專案的 pom.xml 並找到 id 為 "shell" 的元素。
  • 將 activeByDefault 標誌更改為 true,然後等待 Q4E 下載相依性。
  • 使用 Q4E 可視化工具檢查相依性(右鍵單擊專案並選擇 Maven2->分析相依性(或可視化相依性)。你只需要這樣做才能看到傳遞相依性是什麼。(你也可以使用$ mvn dependency:tree在命令列上。)
  • 此時,我總是右鍵單擊專案並選擇 Maven2->獲取原始碼 JAR。這是可選的,但可以使開發更容易並使調試成為可能。
  • 將直接相依性複製到平台bundles/usr目錄。嚴格來說,你只需要複製那些尚未在bundles/ext中的那些。在命令列上(使用合理的作業系統),你可以執行
    $ find ~/.m2/repository -name \*.jar -exec cp {} bundles/usr \;
    
  • 你可能需要在套件專案中的某些或所有MANIFEST.MF檔案上進行「虛假編輯」以強制工具刷新。
  • 將 activeByDefault 標誌切換回 false。

無需重新啟動 Eclipse 或任何東西。「套件相依性」類別路徑容器應包含你剛剛下載的執行時期相依性。當問題視圖中的所有 Eclipse 錯誤(憤怒的紅色邊距標記)都消失時,我們就可以開始了。

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

Beta5 更新

使用 beta5,你不需要「尋找和複製」步驟,因為 platform.config 允許你指向本地 Maven 儲存庫作為相依性的來源,而不是 bundles/usr。

原則上,你根本不需要用於執行時期相依性的 Maven 本地儲存庫。你可以打開平台執行階段(在伺服器視圖中右鍵單擊並打開),然後直接瀏覽並下載相依性到bundles/usr。目前唯一的弱點(工具團隊正在努力改進這一點)是它不提供任何傳遞相依性的視圖 - 你必須明確知道需要哪些套件。對於此部落格的範例來說,這很容易,因為 MANIFESTs 都已經完全指定了相依性。當你不確定它們是什麼並且必須從頭開始建立 MANIFEST 時,這會更困難。為此,我現在仍然使用 Q4E。

總結

條條大路通羅馬,平台是一個非常豐富的環境,因此你可以確定我在此展示的不是在平台中運行 Job 的唯一方法。希望這是一個好的起點。

Application Platform 1.0 版本的大部分重點都在網路層,雖然這顯然是必不可少的(而且非常難以實現),但還有其他目標需要努力。 2.0 版本將具有特定的批次相關功能(批次個性),因此我們現在所做的任何事情都將有助於充實該版本的特性要求。因此,如果你有機會嘗試一下並有一些建設性的意見,特別是關於操作方面的,它們將在我們開始構建批次個性時派上用場。

取得 Spring 電子報

訂閱 Spring 電子報,與我們保持聯繫

訂閱

更上一層樓

VMware 提供培訓和認證,以加速你的進展。

了解更多

獲得支援

Tanzu Spring 在一個簡單的訂閱中提供對 OpenJDK™、Spring 和 Apache Tomcat® 的支援和二進位檔案。

了解更多

即將到來的活動

查看 Spring 社群中所有即將到來的活動。

查看全部