領先一步
VMware 提供培訓和認證,助您加速進步。
瞭解更多我們一直在努力開發 Spring Batch,為 Spring Portfolio 2.5 版本系列做準備,我認為現在是時候向大家更新一下情況了。在這篇文章中,我將稍微擴充套件一下領域模型,以及我們提高一些核心領域物件知名度、增加其職責的決定。我還會提供一些即將到來的、直至 1.0 的版本的一些預覽,以便大家有機會發表評論。
作為道歉:自上次我撰寫關於 Spring Batch 的部落格以來,其內部發生了一些相當重大的變化,所以我感覺自己疏忽了。在這篇文章中,我認為我無法涵蓋所有更改,但我保證將來會努力保持更新,並且在 1.0 版本釋出臨近時,我一定會讓大家及時瞭解最新情況。(注意:Spring Portfolio 2.5 釋出列車包含 Spring Batch 1.0。)
由於我們自 1.0.0-m3 以來修復了 70 多個問題,我們覺得是時候釋出一些東西了。我們上週制定的計劃是明天(2 月 5 日)釋出 1.0.0-m4,範圍比原計劃略窄(例如,推遲 XML 名稱空間實現)。然後 1.0.0-m5 將在大約 10-14 天后釋出,這樣在 3 月 20 日 1.0.0 最終釋出之前,至少有時間釋出一個候選版本。
Spring Batch 核心是一個非常緊湊的 API。實際上,它幾乎不包含我們期望批處理應用程式開發人員實現或擴充套件的任何內容,因此它實際上是一個內部 API。儘管如此,它對 Spring Batch 使用者產生了相當深遠的影響,因為它塑造了我們思考批處理作業及其執行方式,以及(對使用者來說更重要的是)其實現、配置和部署方式。
在 1.0.0-m3 之前,我們遇到了一個經典的 API 與批處理領域通用語言不匹配的案例。我們不得不一直解釋說JobConfiguration是大多數人所說的“作業”(對於StepConfiguration和“步驟”也是如此)。“作業”是您配置每天執行的東西,但每次執行時,它都有一個新的標識。這是一個明確的訊號,“作業”是領域概念的名稱,那麼我們為什麼要稱之為“JobConfiguration”呢?好問題。所以現在(在 1.0.0-m4 中)使用者配置的東西是作業,當它執行時,我們建立一個新的JobInstance。對於Step還是StepInstance也是如此。因此,實體原型由*Instance物件實現——它們在資料庫中具有 id 和主鍵。一個例子是 [JobInstance2008 年 2 月 2 日生效],用於 ["end-of-day"作業].
另一個實體原型是StepExecution還是StepExecution。自 m3 以來,它們的名稱和職責沒有改變。當一個JobInstance被執行時,我們建立一個StepExecution(首先確保該例項尚未執行)。此時,[StepExecution2 月 2 日晚上 10 點],[JobInstance2008 年 2 月 2 日生效] 的 ["end-of-day"作業] 啟動。但如果它失敗了,並在第二天重新啟動,那麼我們需要一個新的 [StepExecution2 月 3 日晚上 10:12] 用於相同的JobInstance(即 [JobInstance2008 年 2 月 2 日生效] 的 ["end-of-day"作業])。因此作業與JobInstance是一對多的關係,後者又與StepExecution是一對多的關係。這同樣適用於Step*.
我們還在 1.0.0-m4 中對 API 進行了更改,涉及作業還是Step的執行。在 1.0.0-m3 之前,我們為每個執行都有一個單獨的介面——JobExecutor執行作業和StepExecutor執行Step。正如我們當時設計時所認為的,這具有封裝的優點——我們設想了多個StepExecutor的實現都能夠執行相同的Step。在實踐中,隨著我們對實現輪廓的瞭解越來越多,我們發現這是一個人為的區別。有趣的是,訊號是我們在 Java 的StepExecutor實現中進行了太多“instanceof”檢查——它們總是必須針對不同的Step實現做特殊處理。最終很明顯,每個Step都必須知道如何執行自己。與所有此類見解一樣,當你看到它時,它是顯而易見的,但在此之前,它絕不是如此。謝謝 Eric Evans。
因此,例如,Step領域的核心介面是
public interface Step {
// ... properties that the Job needs to know here ...
void execute(StepExecution stepExecution)
throws StepInterruptedException, BatchCriticalException;
}
沒有必要讓Step從execute方法返回任何內容,因為傳入的StepExecution會在步驟執行過程中更新。它由呼叫者傳入,如果需要,可以用於監控執行進度。如果呼叫者需要中斷作業(因此出現StepInterruptedException),它也可以用於停止執行,只需設定一個標誌setTerminateOnly()。這是幾個人問過我的問題,所以這裡可能值得一提:Step負責在任何可能的地方檢查該標誌的值,因此框架中內建了一種機制用於發出作業提前終止的訊號。設定該標誌的效果取決於Step的實現,但我們提供了一個SimpleStep,它會在處理完每個專案後檢查該標誌,並在必要時中止。它還接受一個StepInterruptPolicy策略,可用於檢查其他異常情況(例如Thread.isInterrupted()).
Spring Batch 幾乎是 Spring XML 名稱空間如何幫助應用程式開發人員簡化工作的完美示例。我們尚未實現NamespaceHandler,但它已安排在下一個里程碑 1.0.0-m5 中,所以現在是您感受示例的好時機。
座右銘是“讓配置看起來像領域模型”,本著這種精神,請看這個例子,看看它是否有意義。它是新名稱空間的一個草案,模仿了現有的固定長度匯入示例作業,因此熟悉它的人會看到其中的相似之處。如果您需要查詢現有示例,只需訪問 Spring Batch 主頁下載釋出版本(固定長度示例配置也可以在此處瀏覽)。
<batch>
<job id="fixedLengthImportJob" volatile="false">
<simple-step id="step1" chunk-size="50" save-restart-data="false"
allow-start-if-complete="true" reader-ref="fileInputTemplate">
<processor>
<beans:bean
class="org.springframework.batch.sample.item.processor.TradeProcessor">
<property name="writer" ref="tradeDao" />
</beans:bean>
</processor>
<simple-completion-policy skipLimit="5" />
</simple-step>
<simple-step id="step2" chunk-size="200">
<jdbc-cursor-reader data-source-ref="dataSource">
<query><![CDATA[SELECT ID FROM T_TRADE ORDER BY ID WHERE PROCESSED='N']]></query>
</jdbc-cursor-reader>
<processor>
<beans:bean
class="org.springframework.batch.sample.item.processor.TradeUpdater">
<property name="dao" ref="tradeDao" />
</beans:bean>
</processor>
</simple-step>
<tasklet-step id="step3" chunk-size="1">
<tasklet>
<beans:bean
class="org.springframework.batch.sample.sproc.TradeSummarizer"
p:dataSource-ref="dataSource" />
</tasklet>
</tasklet-step>
</job>
<!-- INFRASTRUCTURE SETUP -->
<flat-file-reader id="fileInputTemplate"
resource="data/fixedLengthImportJob/input/20070122.teststream.ImportTradeDataStep.txt"
field-set-mapper-ref="fieldSetMapper"
validator-ref="fixedValidator">
<fixed-length-tokenizer>
<columns>
ISIN=1-12 Quantity=13-15 Price=16-20 Customer=21-29
</columns>
</fixed-length-tokenizer>
</flat-file-reader>
<beans:bean id="fixedValidator"
class="org.springframework.batch.item.validator.SpringValidator">
<property name="validator">
<bean id="tradeValidator"
class="org.springmodules.validation.valang.ValangValidator">
<property name="valang">
<value>
<![CDATA[
{ isin : length(?) < 13 : 'ISIN too long' : 'isin_length' : 12}
]]>
</value>
</property>
</bean>
</property>
</beans:bean>
<beans:bean id="tradeDao"
class="org.springframework.batch.sample.dao.JdbcTradeWriter">
<property name="jdbcTemplate" ref="jdbcTemplate" />
<property name="incrementer">
<bean parent="incrementerParent">
<property name="incrementerName" value="TRADE_SEQ" />
</bean>
</property>
</beans:bean>
<beans:bean id="fieldSetMapper"
class="org.springframework.batch.sample.mapping.TradeFieldSetMapper" />
</batch>
請注意作業還是Step的實現細節是如何隱藏的——<simple-step/>和<tasklet-step/>之間存在差異,但唯一可見的差異是使用者需要知道的那些。使用者不需要知道支援此配置的Step介面有不同的實現,但存在面向專案和麵向任務的步驟方法這一事實並沒有隱藏。這就是我們認為對使用者很重要的。當我們起草這些 XML 示例時,我們從現有的 Spring Batch 示例中提取了幾個例子並進行了修改,直到包含相同的配置資訊,但在大多數情況下,檔案的總大小減少了 50% 或更多。這一定意味著我們走在正確的軌道上。
這是一次非常快速但深入地探討了 Spring Batch 和最近的一些變化。我還可以與您分享更多關於我們使用和實現框架的經驗的有趣細節。我的 JavaOne 演講被接受了,這意味著您可以期待在五月份在舊金山瞭解更多資訊,並聽到更多真實批處理的示例。此外,隨著 2.5 版本釋出列車開始其旅程(從使用者的角度來看!),請關注本部落格上的更多內容。
最後,我需要向 Lucas Ward 和 Ben Hale 致敬,他們在 Spring Batch 的開發過程中發揮了重要作用。我還想歡迎 Robert Kasanicky 成為我們最新的提交者——Robert 為 Spring Batch 貢獻了一些非常高質量的程式碼,我相信在我們將 1.0 收尾並開始下一個主要版本的工作時,他將繼續這樣做。如果其他人有興趣貢獻,Robert 遵循了在論壇和 JIRA 上活躍、貢獻想法和(關鍵是)補丁的正常流程。我提名了他,我們進行了投票,現在他正式成為團隊的一員。
如果文章中有任何需要澄清的地方,請隨時在此處發表評論。有關 Spring Batch 的一般討論,請使用論壇。Spring Batch 的主頁在此處,或者可以輕鬆地從Spring 主網站找到