本文介紹了Spring Batch ItemReader列表僅處理一次的處理方法,對大家解決問題具有一定的參考價值,需要的朋友們下面隨著小編來一起學習吧!
問題描述
我正在嘗試使用ListItemReader<String>
、ItemProcessor<String, String>
和ItemWriter<String>
創建Spring批處理作業。
XML如下所示
<job id="sourceJob" xmlns="http://www.springframework.org/schema/batch">
<step id="step1" next="step2">
<tasklet>
<chunk reader="svnSourceItemReader"
processor="metadataItemProcessor"
writer="metadataItemWriter"
commit-interval="1" />
</tasklet>
</step>
<step id="step2">
<tasklet ref="lastRevisionLoggerTasklet"></tasklet>
</step>
</job>
<bean id="svnSourceItemReader"
class="com.example.repository.batch.SvnSourceItemReader"
scope="prototype">
<constructor-arg index="0">
<list>
<value>doc1.xkbml</value>
<value>doc2.xkbml</value>
<value>doc3.xkbml</value>
</list>
</constructor-arg>
</bean>
<bean id="metadataItemProcessor"
class="com.example.repository.batch.MetadataItemProcessor"
scope="prototype" />
<bean id="metadataItemWriter"
class="com.example.repository.batch.MetadataItemWriter"
scope="prototype" />
閱讀器、處理器和寫入器都是普通的
public class SvnSourceItemReader extends ListItemReader<String> {
public SvnSourceItemReader(List<String> list) {
super(list);
System.out.println("Reading data list " + list);
}
@Override
public String read() {
String out = (String) super.read();
System.out.println("Reading data " + out);
return out;
}
}
public class MetadataItemProcessor implements ItemProcessor<String, String> {
@Override
public String process(String i) throws Exception {
System.out.println("Processing " + i + " : documentId " + documentId);
return i;
}
}
public class MetadataItemWriter implements ItemWriter<String> {
@Override
public void write(List<? extends String> list) throws Exception {
System.out.println("Writing " + list);
}
}
作業按如下方式啟動,但按計劃每10秒啟動一次。
long nanoBits = System.nanoTime() % 1000000L;
if (nanoBits < 0) {
nanoBits *= -1;
}
String dateParam = new Date().toString() + System.currentTimeMillis()
+ "." + nanoBits;
param = new JobParametersBuilder().addString("date", dateParam)
.toJobParameters();
JobExecution execution = jobLauncher.run(job, param);
應用程序啟動時,我看到它讀取、處理和寫入傳遞給讀取器的列表中的三個項目。
Reading data doc1.xkbml
Processing doc1.xkbml : documentId doc1
Writing [doc1.xkbml]
Reading data doc2.xkbml
Processing doc2.xkbml : documentId doc2
Writing [doc2.xkbml]
Reading data doc3.xkbml
Processing doc3.xkbml : documentId doc3
Writing [doc3.xkbml]
因為此sourceJob
使用的是計劃計時器,所以我預計每隔10秒就會看到該列表被處理,但實際上我看到的是所有后續運行。
Reading data null
有人知道為什么會發生這種情況嗎?我是Spring Batch的新手,對這個問題就是摸不著頭腦。
謝謝/w
推薦答案
問題是您將讀者標記為scope="prototype"
。應為scope="step"
。
Spring-Batch中只有兩個作用域:singleton
(默認值)和step
。
來自javadoc:
StepScope:
步驟上下文的范圍。此范圍內的對象使用
Spring容器作為對象工廠,因此只有一個實例
這樣的bean的每個執行步驟。此作用域中的所有對象都
(不需要修飾Bean定義)。
和
需要使用STEP作用域才能使用后期綁定,因為
在步驟開始之前,bean實際上不能被實例化,這
允許查找屬性。
在Spring上下文啟動期間,請查看日志,您將看到以下行:
信息:已從類路徑資源執行完SQL腳本
9毫秒[org/springframework/batch/core/schema-hsqldb.sql]。
讀取數據列表[doc1.xkbml,doc2.xkbml,doc3.xkbml]
如您所見,您的讀取器已經作為單例創建和管理;Spring-Batch上下文中的動態bean應該使用特殊的step
范圍進行管理,以便Spring將在每次執行步驟時創建bean的新副本。
在您的閱讀器中,ListItemReader.read()
寫為:
public T read() {
if (!list.isEmpty()) {
return list.remove(0);
}
return null;
}
從原始列表中刪除每個已讀項目!讀取器構建一次,在第二次執行作業時,列表為空!
這篇關于Spring Batch ItemReader列表僅處理一次的文章就介紹到這了,希望我們推薦的答案對大家有所幫助,