Spring Batch 近期變更與即將發佈的 m4 版本

工程 | Dave Syer | 2008 年 2 月 4 日 | ...

我們一直努力開發 Spring Batch,為 Spring Portfolio 2.5 版本做準備,我想現在是時候讓大家了解最新進度了。在本文中,我將更詳細地介紹領域建模,以及我們決定提高一些核心領域物件的地位並增加其職責的決定。我還將簡要介紹接下來幾個版本中將要發布的內容,以便大家有機會提出意見。

首先要道歉的是:自從我上次寫關於 Spring Batch 的部落格以來,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 Core

Spring Batch Core 是一個相當精簡的 API。它實際上不包含任何我們一定期望批次應用程式開發人員實作或擴展的內容,因此它實際上是一個內部 API。儘管如此,它對 Spring Batch 使用者產生了相當大的影響,因為它塑造了我們對批次作業及其執行方式的思考,並且(對使用者而言更重要的是)其實作、配置和部署方式。

Job 和 Step 以及資料模型

在 1.0.0-m3 之前,我們有一個典型的 API 與批次通用語言不匹配的案例。我們必須不斷解釋JobConfiguration是大多數人認為的 "Job"(對於StepConfiguration和 "Step" 也是如此)。"Job" 是您配置為每天運行的東西,但每次運行時,它都有一個新的身份。這是一個明顯的訊號,表明 "Job" 是領域概念的名稱,那麼我們為什麼要將其稱為 "JobConfiguration"?好問題。所以現在(在 1.0.0-m4 中),使用者配置的東西是一個Job,當它運行時,我們創建一個新的JobInstance。對於StepStepInstance也是如此。因此,Entity 原型由*Instance物件滿足 - 它們具有 id 和資料庫中的主鍵。例如 [JobInstance生效日期為 2008 年 2 月 2 日],適用於 ["end-of-day"Job].

其他 Entity 原型是JobExecutionStepExecution。自 m3 以來,這些物件的名稱或職責沒有改變。當一個JobInstance被執行時,我們創建一個JobExecution(確保實例尚未在執行)。此時,[JobExecution2 月 2 日晚上 10 點] 的 [JobInstance生效日期為 2008 年 2 月 2 日] 的 ["end-of-day"Job],將會啟動。但是,如果它失敗並在第二天重新啟動,那麼我們將需要一個新的 [JobExecution2 月 3 日晚上 10 點 12 分] 用於同一個JobInstance(即 [JobInstance生效日期為 2008 年 2 月 2 日] 的 ["end-of-day"Job])。因此JobJobInstance是一對多關係,而JobExecution又與是一對多關係。同樣的道理適用於.

Step*

Job 和 Step 和 ExecutionJobStep我們還對 1.0.0-m4 中的執行進行了 API 變更。在 1.0.0-m3 之前,我們為每個的執行都有一個單獨的介面 -JobExecutorJob執行,而JobExecutorStepStepExecutor,而。正如我們在設計它時所想的那樣,這具有封裝的好處 - 我們想像Step的多個實作都可以執行同一個,而。實際上,隨著我們對實作輪廓的了解越來越多,我們發現這是一種人為的區別。有趣的是,這個訊號是我們在 Java 中有太多 "instanceof" 檢查,位於我們的Step實作中 - 它們總是必須為不同的Step實作進行特殊處理。最後,很明顯每個

都必須知道如何執行自己。與所有此類見解一樣,當您看到它時,它很明顯,但在此之前,它絕非如此。感謝 Eric EvansStep因此,例如,


public interface Step {

    // ... properties that the Job needs to know here ...

    void execute(StepExecution stepExecution) 
         throws StepInterruptedException, BatchCriticalException;

}

領域的核心介面是Step沒有必要讓executeStepExecution方法返回任何內容,因為傳入的在 step 的進度中會被更新。它由呼叫者傳入,如果需要,可用於監視執行的進度。如果呼叫者需要中斷作業,它也可以用於停止執行(因此有StepInterruptedException),只需設定一個標誌setTerminateOnly()Step。這是幾個人問過我的問題,所以這裡值得一提:Step負責盡可能檢查該標誌的值,因此框架內建了一種機制,用於發出作業提早終止的訊號。設定標誌的效果取決於的實作,但我們提供了一個SimpleStep,它會在處理完每個項目後檢查標誌,並在必要時中止。它還接受一個StepInterruptPolicy策略,可用於檢查其他異常情況(例如).

Thread.isInterrupted()

Spring Batch 命名空間Spring Batch 幾乎是 Spring XML 命名空間可以幫助應用程式開發人員更輕鬆地完成工作的完美範例。我們尚未實作NamespaceHandler

,但已安排在下一個里程碑 1.0.0-m5 中,因此現在是您了解範例的感受的好時機。


<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>

座右銘是 "讓配置看起來像領域模型",本著這種精神,請看一下這個範例,看看它是否有意義。它是新命名空間的一個草案,模仿現有的固定長度匯入範例作業,因此熟悉該作業的人將會看到相似之處。如果您需要找到現有的範例,只需前往 Spring Batch 首頁下載版本(也可以 在此處 瀏覽固定長度範例配置)。JobStep請注意的實作細節是如何隱藏的 -<simple-step/><tasklet-step/>Step之間存在差異,但唯一可見的差異是用戶必須知道的差異。使用者不需要知道支援此配置的

介面有不同的實作,但步驟有面向項目和面向任務的方法這一事實並未隱藏。我們認為這對使用者很重要。當我們起草這些 XML 範例時,我們從現有的 Spring Batch 範例中提取了幾個範例,並進行了修改,直到包含相同的配置資訊,但在大多數情況下,檔案的總大小減少了 50% 或更多。這一定意味著我們走在正確的軌道上。

後記

這是一次非常快速但相當深入地探索 Spring Batch 和一些最近的變更。關於我們使用和實作框架的經驗,我可以與您分享更多有趣的資訊。我的 JavaOne 簡報已被接受,這意味著您可以期待在 5 月在舊金山了解更多資訊,並聽到更多關於實際批次處理的範例。此外,請密切關注此部落格,因為 2.5 版本即將開始它的旅程(從使用者的角度來看!)。

最後,我需要向 Lucas Ward 和 Ben Hale 致敬,他們在 Spring Batch 開發過程中發揮了重要作用。我也想歡迎 Robert Kasanicky 成為我們最新的提交者 - Robert 為 Spring Batch 貢獻了一些非常高品質的程式碼,我確信他會繼續這樣做,因為我們即將完成 1.0 並開始開發下一個主要版本。如果有人有興趣貢獻,Robert 遵循了在論壇和 JIRA 上參與討論、貢獻想法和(至關重要的)修補程式的正常流程。我提名了他,我們進行了投票,現在他正式成為團隊的一員。

如果您需要澄清文章中的任何內容,請隨時在此處發表評論。有關 Spring Batch 的一般討論,請使用 論壇。Spring Batch 的首頁是 這裡,或者可以從 Spring 主網站 輕鬆找到。

取得 Spring 電子報

隨時掌握 Spring 電子報的最新消息