chapter 3、Batch configuration
1、spring batch 的命名空間
spring xml中指定batch的前綴作為命名空間。
示例:
- <?xml version="1.0" encoding="UTF-8"?>
- <beans xmlns="http://www.springframework.org/schema/beans"
- xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xmlns:batch="http://www.springframework.org/schema/batch"
- xsi:schemaLocation="http://www.springframework.org/schema/beans
- http://www.springframework.org/schema/beans/spring-beans.xsd
- http://www.springframework.org/schema/batch
- http://www.springframework.org/schema/batch/spring-batch.xsd">
- <batch:job id="importProductsJob">
- (...)
- </batch:job>
- </beans>
當指定batch命名空間之后,bean中的聲明都需要加上batch的前綴,例如:<batch:job id="importProductsJob">
spring的命名空間的前綴可以指定任意的名稱,這里采用batch作為前綴,為了方便理解。
2、spring batch XML的主要標簽有:job、step、tasklet、chunk、job-repository
3、Job配置。job元素是整個配置的頂級元素,它的屬性有:
a、id
b、restartable
c、incrementer
d、abstract
e、parent
f、job-repository
restartable 屬性如果是false,則程序不允許重啟。如果發生重啟,會拋出JobRestartException異常。
- <batch:job id="importProductsJob" restartable="false">
- (...)
- </batch:job>
job除了這些屬性外,還可以配置驗證器<batch:validator ref="parameterValidator" />,用來校驗工作參數(job parameters),可以實現JobParametersValidator接口。
如果無法通過驗證,會拋出JobParametersInvalidException異常。spring batch提供了一個默認的實現類DefaultJobParametersValidator,完成絕大部分的工作。如果還是無法滿足需求,可以自己編碼實現接口。
實例:
- <batch:job id="importProductsJob">
- (...)
- <batch:validator ref="validator"/>
- </batch:job>
- <bean id="validator" class="org.springframework.batch.core.job.DefaultJobParametersValidator">
- <property name="requiredKeys">
- <set>
- <value>date</value>
- </set>
- </property>
- <property name="optionalKeys">
- <set>
- <value>productId</value>
- </set>
- </property>
- </bean>
4、step步驟的配置。
step的屬性:
a、next
b、parent
c、abstract
示例:
- <job id="importProductsJob">
- <step id="decompress" next="readWrite">
- (...)
- </step>
- <step id="readWrite">
- (...)
- </step>
- </job>
5、tasklet和chunk的配置。
tasklet和chunk是用來指定處理過程的。
一個tasklet對應於一個事務性的、潛在可重復的過程中發生的一個步驟。
你可以自己實現Tasklet 接口,定義自己的tasklet。這個特性很有用,比如:用於解壓文件,執行系統命令,執行存儲過程等待。
你也可以使用系統tasklet的屬性有:
a、ref指定應用的bean
b、transaction-manager事物管理器
c、start-limittasklet重試retry的次數
d、allow-start-if-complete如果tasklet成功完成之后,是否可以進行重試retry操作。
示例:
- <batch:job id="importProductsJob">
- (...)
- <batch:step id="readWriteStep">
- <batch:tasklet
- transaction-manager="transactionManager"
- start-limit="3"
- allow-start-if-complete="true">
- (...)
- </batch:tasklet>
- </batch:step>
- </batch:job>
- <bean id="transactionManager" class="(...)">
- (...)
- </bean>
chunk ,ChunkOrientedTasklet 類實現類“塊處理(chunk processing)”。
配置tasklet很簡單,但是配置“塊處理”就會復雜一點,因為它涉及的內容更多。
chunk的屬性有:
a、reader
b、processor
c、writer
d、commit-interval事物提交一次處理的items的數量。也是chunk的大小。
e、skip-limit跳躍的次數
f、skip-policy跳躍的策略:要實現SkipPolicy接口
g、retry-policy重試的策略:要實現RetryPolicy接口
h、retry-limit最大的重試次數
i、cache-capacity重試的緩存策略
j、reader-transactional-queue從一個擁有事務的JMS的queue讀取item數據
k、processor-transactional處理器是否包含事務處理
l、chunk-completion-policychunk的完成策略
示例:
- <batch:job id="importProductsJob">
- (...)
- <batch:step id="readWrite">
- <batch:tasklet>
- <batch:chunk
- reader="productItemReader"
- processor="productItemProcessor"
- writer="productItemWriter"
- commit-interval="100"
- skip-limit="20"
- retry-limit="3"
- cache-capacity="100"
- chunk-completion-policy="timeoutCompletionPolicy"/>
- </batch:tasklet>
- </batch:step>
- </batch:job>
- <bean id="productItemReader" class="(...)">
- (...)
- </bean>
- <bean id="productItemProcessor" class="(...)">
- (...)
- </bean>
- <bean id="productItemWriter" class="(...)">
- (...)
- </bean>
- <bean id="timeoutCompletionPolicy"
- class="org.springframework.batch.repeat.policy.TimeoutTerminationPolicy">
- <constructor-arg value="60"/>
- </bean>
chunk還有幾個子標簽,包括:reader、processor、writer、skip-policy、retry-policy
示例:
- <batch:job id="importProductsJob">
- (...)
- <batch:step id="readWrite">
- <batch:tasklet>
- <batch:chunk commit-interval="100">
- <batch:reader>
- <bean class="(...)">
- (...)
- </bean>
- </batch:reader>
- <batch:processor>
- <bean class="(...)">
- (...)
- </bean>
- </batch:processor>
- <batch:writer>
- <bean class="(...)">
- (...)
- </bean>
- </batch:writer>
- </batch:chunk>
- </batch:tasklet>
- </batch:step>
- </batch:job>
chunk的一些其他額外的子標簽:retry-listeners、skippable-exception-classes、retryable-exception-classes、streams
示例:
- <batch:job id="importProductsJob">
- (...)
- <batch:step id="readWrite">
- <batch:tasklet>
- <batch:chunk commit-interval="100"
- skip-limit="10">
- <skippable-exception-classes>
- <include class="org.springframework.batch.item.file.FlatFileParseException"/>
- <exclude class="java.io.FileNotFoundException"/>
- </skippable-exception-classes>
- </batch:chunk>
- </batch:tasklet>
- </batch:step>
- </batch:job>
在chunk里面配置streams
示例:
- <batch:job id="importProductsJob">
- (...)
- <batch:step id="readWrite">
- <batch:tasklet>
- <batch:chunk reader="productItemReader" writer="compositeWriter"/>
- <streams>
- <stream ref="productItemWriter1"/>
- <stream ref="productItemWriter2"/>
- </streams>
- </batch:tasklet>
- </batch:step>
- </batch:job>
- <bean id="compositeWriter"
- class="org.springframework.batch.item.support.CompositeItemWriter">
- <property name="delegates">
- <list>
- <ref bean="productItemWriter1"/>
- <ref bean="productItemWriter2"/>
- </list>
- </property>
- </bean>
使用一個復合的stream形式,如上例的itemWriter,內部是writer1和writer2是stream的,需要在chunk里面的streams元素里面注冊。
6、事務配置。
事務是spring batch的一個重要主題。主要作用於batch處理程序的健壯性,chunk處理的合並來完成它的工作。因為事務調用的對象類型不同,你可以在不同的層次配置事務。
示例:
- <batch:job id="importProductsJob">
- (...)
- <batch:step id="readWrite">
- <batch:tasklet transaction-manager="transactionManager" (...)>
- (...)
- </batch:tasklet>
- </batch:step>
- </batch:job>
事務,有幾個定義的屬性:行為,隔離 isolation,超時 timeout。
spring batch提供transaction-attributes標簽來描述這些事務的屬性。
示例:
- <batch:tasklet>
- <batch:chunk reader="productItemReader"
- writer="productItemReader"
- commit-interval="100"/>
- <batch:transaction-attributes isolation="DEFAULT"
- propagation="REQUIRED"
- timeout="30"/>
- </batch:chunk>
- </batch:tasklet>
isolation 定義數據庫的隔離級別以及對外部事務的可見性。
spring的事務處理是基於java的異常體系的。java里面的異常分為兩類:檢查型異常(extends Exception)和非檢查型異常(extends RuntimeException)
spring對檢查型異常進行commit提交處理,對非檢查型異常進行rollback回滾處理。
spring batch運行你對不需要觸發rollback回滾動作的異常進行定義。你可以在tasklet的no-rollback-exception-class元素中進行指定。
示例:
- <batch:tasklet>
- (...)
- <batch:no-rollback-exception-classes>
- <batch:include
- class="org.springframework.batch.item.validator.ValidationException"/>
- </batch:no-rollback-exception-classes>
- </batch:tasklet>
對於JMS,spring batch提供chunk的reader-transactional-queue 屬性,提供事務處理。
7、配置job倉庫
job倉庫(job repository)是spring batch底層基礎的一個關鍵特征,它為spring batch的運行提供信息。
job倉庫必須實現JobRepository接口,spring batch只提供了一個具體的實現類:SimpleJobRepository。
spring batch為DAO提供了兩種實現:
a、內存無持久化
b、jdbc元數據的持久化
第一種“內存無持久化”的方式可以用來spring batch的測試和開發,但是不能應用於生產環境。因為內存中的東西會丟失。
設定job倉庫的參數
(1)、配置內存模式的job倉庫:Configuring an in-memory job repository
示例:
- <bean id="jobRepository" class="org.springframework.batch.core.repository.support.MapJobRepositoryFactoryBean">
- <property name="transactionManager-ref" ref="transactionManager"/>
- </bean>
- <bean id="transactionManager" class="org.springframework.batch.support.transaction.ResourcelessTransactionManager"/>
- <batch:job id="importInvoicesJob" job-repository="jobRepository">
- (...)
- </batch:job>
由於job倉庫是內存模式的,所以事務管理器采用ResourcelessTransactionManager。 這個類是NOOP (NO OPeration)無操作的PlatformTransactionManager接口實現。
(2)、持久化的job倉庫:Configuring a persistent job repository
關系型數據庫的job倉庫的屬性如下:data-source,transaction-manager,isolation-level-for-create,max-varchar-length,table-prefix,lob-handler
示例:
- <bean id="dataSource"
- class="org.apache.commons.dbcp.BasicDataSource"
- destroy-method="close">
- <property name="driverClassName" value="${batch.jdbc.driver}" />
- <property name="url" value="${batch.jdbc.url}" />
- <property name="username" value="${batch.jdbc.user}" />
- <property name="password" value="${batch.jdbc.password}" />
- </bean>
- <bean id="transactionManager" lazy-init="true"
- class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
- <property name="dataSource" ref="dataSource" />
- </bean>
- <batch:job-repository id="jobRepository"
- data-source="dataSource"
- transaction-manager="transactionManager"
- isolation-level-for-create="SERIALIZABLE"
- table-prefix="BATCH_"
- />
- <batch:job id="importInvoicesJob" job-repository="jobRepository">
- (...)
- </batch:job>
[問題:如果在不同的物理節點上面運行同樣的job會發生什么呢?]
前提:使用同一份spring batch的元數據,即采用同一份數據庫上面的表結構。
當創建job實例和執行信息的元數據的時候,job倉庫扮演了一個集中維護的工作庫的角色。當job並發運行的時候,spring batch 的job倉庫,可以防止創建相同的工作情況。這個功能依賴於底層數據庫的事務能力,完成job的同步任務。我們設置job倉庫的屬性isolation-level-for-create="SERIALIZABLE",來避免發生job的並發問題。由於有這種防護措施,你可以把你的spring batch的job分布到各個不同的物理節點,保證你的job實例不會被創建兩次。
job倉庫是spring batch底層結構中的重要部分,它記錄了batch處理的信息,並且跟蹤job運行的成功與失敗。
8、spring batch配置的高級主題。
(1)、使用step作用域。當使用SpEL的時候,step作用域很有用,來實現屬性的晚綁定。
(2)、Spring表達式語言:Spring Expression Language (SpEL)
Spring3.× 開始提供。
step的作用的實例范圍包括:jobParameters、jobExecutionContext、stepExecutionContext
示例:
- <bean id="decompressTasklet"
- class="com.manning.sbia.ch01.batch.DecompressTasklet"
- scope="step">
- <property name="inputResource"
- value="#{jobParameters['inputResource']}" />
- <property name="targetDirectory"
- value="#{jobParameters['targetDirectory']}" />
- <property name="targetFile"
- value="#{jobParameters['targetFile']}" />
- </bean>
SpEL由 #{ 和 } 組成
在jobExecutionContext 和 stepExecutionContext也可以應用SpEL表達式。
(3)、使用Linteners提供的更多的處理。
Spring batch在job和step級別上面提供listener。
Spring batch提供的listener的類型:
a、Job listener:在job級別監聽處理過程
b、Step listeners:在step級別監聽處理過程
c、Item listeners:監聽item的retry重試和repeat重做動作
一、Job listener 可以監聽job的運行,在job運行前和后添加動作。可以利用 listener標簽,在job標簽下面作為子元素進行添加。
示例1:
- <batch:job id="importProductsJob">
- <batch:listeners>
- <batch:listener ref="importProductsJobListener"/>
- </batch:listeners>
- </batch:job>
importProductsJobListener不管job運行成功還是失敗,它都會在job運行的開始和結束的時候,接收job的通知,進行監聽。
還可以通過普通的POJO的java對象來做監聽器,只需要進行簡單的配置即可。
示例2:
- <batch:listeners>
- <batch:listener ref="importProductsJobListener" after-job-method="afterJob" before-job-method="beforeJob"/>
- </batch:listeners>
可以在listener里面的ref指定引用的POJO的bean,通過after-job-method="afterJob" before-job-method="beforeJob" 來指定job之前和之后的執行方法。不過,被指定的這兩個方法的參數都需要是:JobExecution jobExecution。 這個2個方法的返回值都是void
還有一種方法是利用“注釋”來配置listener,spring batch會自己發現並運行該類。
二、Step listener
Step有一系列的listener來跟蹤step的處理過程。這里所有的listener接口都繼承了StepListener接口。
Spring batch提供的Step的listener有:
a、ChunkListener:在chunk執行的之前和之后調用。
b、ItemProcessListener:在 ItemProcessor得到一個item之前和之后調用,在ItemProcessor拋出一個異常的時候調用。
c、ItemReadListener:在讀取item之前和讀取item之后調用,或者在讀取item的過程中觸發異常的時候調用。
d、ItemWriteListener:在一個item輸出之前和之后調用,或者在item輸出的過程中調用。
e、SkipListener:當讀取、處理和輸出的過程中產生了skip跳躍一個item的時候調用。
f、StepExecutionListener:在step運行之前和之后調用。
接口代碼:
- public interface StepExecutionListener extends StepListener {
- void beforeStep(StepExecution stepExecution);
- ExitStatus afterStep(StepExecution stepExecution);
- }
- public interface ChunkListener extends StepListener {
- void beforeChunk();
- void afterChunk();
- }
- public interface ItemProcessListener<T, S> extends StepListener {
- void beforeProcess(T item);
- void afterProcess(T item, S result);
- void onProcessError(T item, Exception e);
- }
- public interface ItemReadListener<T> extends StepListener {
- void beforeRead();
- void afterRead(T item);
- void onReadError(Exception ex);
- }
- public interface ItemWriteListener<S> extends StepListener {
- void beforeWrite(List<? extends S> items);
- void afterWrite(List<? extends S> items);
- void onWriteError(Exception exception, List<? extends S> items);
- }
- public interface SkipListener<T,S> extends StepListener {
- void onSkipInRead(Throwable t);
- void onSkipInProcess(T item, Throwable t);
- void onSkipInWrite(S item, Throwable t);
- }
Step listener 作為tasklet標簽的一個子標簽進行配置。
上面這些所有的Step listener都可以作為tasklet標簽的子標簽以相同的方式和等級進行配置。
示例:
- <bean id="importProductsJobListener"
- class="test.case01.java.batch.listener.job.ImportProductsJobListener" />
- <bean id="productStepExecutionListener"
- class="test.case01.java.batch.listener.step.ProductStepExecutionListener" />
- <bean id="productChunkListener"
- class="test.case01.java.batch.listener.step.chunk.ProductChunkListener" />
- <bean id="productItemProcessListener"
- class="test.case01.java.batch.listener.step.chunk.item.ProductItemProcessListener" />
- <batch:job id="importProducts" restartable="false">
- <batch:step id="readWriteProducts">
- <batch:tasklet>
- <batch:chunk reader="reader" writer="writer" processor="processor"
- commit-interval="100" skip-limit="5">
- <batch:skippable-exception-classes>
- <batch:include
- class="org.springframework.batch.item.file.FlatFileParseException" />
- </batch:skippable-exception-classes>
- </batch:chunk>
- <batch:listeners>
- <!-- here configure three kinds listeners for StepExecutionListener , ChunkListener , ItemProcessListener for example.-->
- <batch:listener ref="productStepExecutionListener" />
- <batch:listener ref="productChunkListener" />
- <batch:listener ref="productItemProcessListener" />
- </batch:listeners>
- </batch:tasklet>
- </batch:step>
- <batch:validator ref="parameterValidator" />
- <batch:listeners>
- <batch:listener ref="importProductsJobListener" />
- </batch:listeners>
- </batch:job>
三、retry重試和repeat重做的listener
repeat listener擁有的方法名稱:before、after、close(在一個item最后一次repeat重做之后調用,不管repeat成功與否)、onError、open
retry listener擁有的方法名稱:close(在一個item上面最后一次嘗試retry之后調用,不管retry成功與否)、onError、open
接口代碼:
- public interface RepeatListener {
- void before(RepeatContext context);
- void after(RepeatContext context, RepeatStatus result);
- void open(RepeatContext context);
- void onError(RepeatContext context, Throwable e);
- void close(RepeatContext context);
- }
- public interface RetryListener {
- <T> void open(RetryContext context, RetryCallback<T> callback);
- <T> void onError(RetryContext context,
- RetryCallback<T> callback, Throwable e);
- <T> void close(RetryContext context,
- RetryCallback<T> callback, Throwable e);
- }
這2個接口,和上面的step listener的配置位置和方式一致,都是tasklet標簽的子標簽位置
四、配置繼承關系
spring的XML提供配置的繼承。使用abstract和parent兩個屬性。從一個parent的bean繼承,表示該bean可以利用parent bean中的所有的屬性,並且可以覆蓋這些屬性。
示例:
- <bean id="parentBean" abstract="true">
- <property name="propertyOne" value="(...)"/>
- </bean>
- <bean id="childBean" parent="parentBean">
- <property name="propertyOne" value="(...)"/>
- <property name="propertyTwo" value="(...)"/>
- </bean>
這種繼承關系是由spring提供的,在spring batch里面也可以使用。
listeners標簽,提供merge屬性,可以用來合並parent和自身的listener
示例:
- <job id="parentJob" abstract="true">
- <listeners>
- <listener ref="globalListener"/>
- <listeners>
- </job>
- <job id="importProductsJob" parent="parentJob">
- (...)
- <listeners merge="true">
- <listener ref="specificListener"/>
- <listeners>
- </job>
spring XML的這種繼承關系,使得spring batch的XML配置更簡單。