搶先一步
VMware 提供培訓和認證,助你突飛猛進。
瞭解更多在本文中,我將展示如何在 SpringSource 應用平臺中執行 Spring Batch 作業。我曾在 JavaOne 上演示過這個的早期版本,後來又在倫敦 Spring 使用者組演示過,覺得這可能是個值得分享的好東西。示例程式碼請點選這裡。
bundle 的配置在META-INF/spring/module-context.xml(這對於平臺 bundle 來說是約定俗成的)—— Spring DM 會從META-INF/spring中載入所有 XML 檔案。這個 bundle 只是使用 Spring 配置並啟動 HSQL Server 例項。
有一個整合測試可以用來檢查配置。
Eclipse 專案還包含一個 HSQL Swing 客戶端的啟動配置,這樣你就可以在 GUI 中檢視資料庫內容。啟動它,並使用META-INF/batch-hsql.properties同一專案中的屬性(url=jdbc:hsqldb:hsql://:9005/samples)連線到伺服器例項。
bundle 的配置在META-INF/spring/module-context.xml像往常一樣。它是simple-job-launcher-context.xml從 Spring Batch 示例中剝離出來的版本。它只需要定義將要匯出的 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-source上面 bundle 暴露的 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 特定的上下文是分開的。這使我們能夠為模組上下文編寫整合測試,而無需部署到平臺。因此我們有
@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 中以常規方式執行測試。
...
Export-Package: com.springsource.consulting.batch.support
...
如果你檢視這個包,你會發現一個便利類,其他 bundle 可以用它來啟動作業(SimpleJobLauncherBean)。TheSimpleJobLauncherBean是一個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")已在上面的資料庫查詢中看到,表明該步驟已執行(一次)。該步驟所做的只是從一個平面檔案中讀取資料,將行轉換為領域物件,並將它們寫入標準輸出。你可以透過檢查平臺主目錄中的跟蹤日誌來檢視結果,例如,如果你執行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 事件,原則上就可以非常靈活地擴充套件它。這些功能可能會在平臺 2.0 版本的 Batch Personality 中看到。如果您對應該有的行為以及操作員需要哪些功能有任何想法,請透過對本文發表評論來幫助我們。
我們可以透過登入 Equinox 控制檯來驗證作業 bundle 的狀態。如果你進入命令列並輸入telnet localhost 2401你應該會看到平臺命令列提示符
osgi>
輸入 "ss" 並按回車,你將看到已安裝 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 是 job launcher,它處於活動狀態。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 和其下的伺服器型別,並使用瀏覽對話方塊找到平臺安裝位置。
$ find ~/.m2/repository -name \*.jar -exec cp {} bundles/usr \;
無須重啟 Eclipse 或其他任何東西。“Bundle Dependencies”類路徑容器應該包含你剛剛下載的執行時依賴項。當 Problems 檢視中所有的 Eclipse 錯誤(憤怒的紅色標記)都消失後,我們就可以開始了。
我很高興聽到有更好方法的人分享經驗。其他人已經發展出了其他方法,但在我看來都不太方便。實際上,一個命令列 Maven 目標會很容易編寫,但我還沒有看到這樣的。
原則上,你根本不需要 Maven 本地倉庫來獲取執行時依賴項。你可以開啟平臺執行時(在 Servers 檢視中右鍵單擊並選擇 Open),然後直接瀏覽並下載依賴項到bundles/usr。目前唯一的缺點(工具團隊正在努力改進這一點)是它不提供任何傳遞性依賴項的檢視——你必須明確知道需要哪些 bundle。對於本部落格的示例,這很容易,因為所有的 MANIFESTs 都已經完整地指定了依賴項。當你不知道它們是什麼並且必須從頭建立 MANIFEST 時,這就更困難了。為此,我目前仍然使用 Q4E。
應用平臺 1.0 版本的大部分重點在於 Web 層,雖然這顯然是必不可少(且非常棘手)的功能,但還有其他更重要的事情要做。2.0 版本將具有特定的批處理相關功能(一個 Batch Personality),因此我們現在所做的任何事情都將有助於充實該版本的特性需求。因此,如果你有機會嘗試一下並有一些建設性的意見,特別是關於操作方面的,它們將在我們開始構建 Batch Personality 時派上用場。