領先一步
VMware 提供培訓和認證,助您加速進步。
瞭解更多在本文中,我將向您展示如何在 SpringSource Application Platform 中執行 Spring Batch 作業。我之前為 JavaOne 做了一個小演示,然後在倫敦 Spring 使用者組再次進行了演示,我認為分享一下會很有用。示例程式碼 在此處。
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 的配置位於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 執行測試。
...
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 放入正在執行的伺服器例項中。它啟動得很快,由於作業範圍很小,您將立即在批處理元資料中看到效果。在 HSQL Swing GUI 中,您可以執行一些 SQL,例如
SELECT * FROM BATCH_STEP_EXECUTION
並檢視結果,類似這樣
| STEP_EXECUTION_ID | VERSION | STEP_NAME | ... | STATUS | ... |
|---|---|---|---|---|---|
| 0 | 4 | helloWorldStep | ... | 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_ID | VERSION | STEP_NAME | ... | STATUS | ... |
|---|---|---|---|---|---|
| 0 | 4 | helloWorldStep | ... | COMPLETED | ... |
| 1 | 4 | helloWorldStep | ... | COMPLETED | ... |
| 2 | 4 | helloWorldStep | ... | COMPLETED | ... |
如果您剛剛嘗試過,您可能會發現第二次及後續啟動時,資料庫中沒有任何變化。這是預期的,因為您重新啟動了一個成功完成的作業例項,所以它不會再次處理資料。事實上,一個異常是由JobLauncher丟擲的,被SimpleJobLauncherBean捕獲並記錄(因此它會出現在跟蹤日誌中)。
安裝 SpringSource Eclipse 工具後,您需要建立一個伺服器例項。轉到 File->New->Other... 並找到 Server->Server。選擇 SpringSource 和下面的伺服器型別,然後使用瀏覽對話方塊查詢 Platform 安裝。
$ find ~/.m2/repository -name \*.jar -exec cp {} bundles/usr \;
無需重啟 Eclipse 或其他任何操作。“Bundle Dependencies”類路徑容器應包含您剛剛下載的執行時依賴項。當 Problems 檢視中的所有 Eclipse 錯誤(紅色的邊距標記)都消失後,我們就準備好了。
我非常樂意聽到人們有一個更好的方法來做到這一點。其他人已經發展了其他方法,但對我來說似乎都不太方便。實際上,編寫一個命令列 Maven 目標很容易,但我還沒有見過那個。
原則上,您也完全不需要執行時依賴項的 Maven 本地儲存庫。您可以開啟 Platform 執行時(在 Servers 檢視中右鍵單擊並選擇 Open),然後直接瀏覽並下載依賴項到bundles/usr。目前唯一的缺點是(工具團隊正在努力改進它),它沒有提供任何傳遞依賴項的檢視 - 您必須明確知道需要哪些 Bundle。對於本部落格的示例,這很容易,因為 MANIFESTs 都已完全指定了依賴項。當您不確定它們是什麼並且必須從頭開始建立 MANIFEST 時,情況就更糟了。為此,我目前仍在使用 Q4E。
Application Platform 1.0 釋出的大部分重點都在 Web 層,雖然這顯然是必不可少的(並且非常棘手),但還有其他事情需要處理。2.0 版本將具有特定的批處理相關功能(Batch Personality),因此我們現在所做的一切都將有助於充實該版本的關鍵功能需求。因此,如果您有機會嘗試一下,並有一些建設性的意見,特別是關於操作方面的,當我們開始構建 Batch Personality 時,它們將非常有用。