Java Spring Batch ItemReader 列表只处理一次
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/18519645/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Spring Batch ItemReader list processed only once
提问by wsams
I'm trying to create a Spring Batch job using a ListItemReader<String>
, ItemProcessor<String, String>
and ItemWriter<String>
.
我正在尝试使用ListItemReader<String>
,ItemProcessor<String, String>
和ItemWriter<String>
.
The XML looks like the following,
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" />
The reader, processor and writer are vanilla,
读取器、处理器和写入器是普通的,
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);
}
}
The job is started like this, but on a schedule of every 10 seconds.
作业是这样开始的,但每 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);
When the application starts, I see it read, process and write each of the three items in the list passed to the reader.
当应用程序启动时,我看到它读取、处理和写入传递给读取器的列表中的三个项目中的每一个。
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]
Because this sourceJob
is on a scheduled timer, every 10 seconds I expected to see that list processed, but instead I see on all subsequent runs.
因为这sourceJob
是在预定的计时器上,所以我希望每 10 秒看到该列表被处理一次,但我却在所有后续运行中看到。
Reading data null
Does anyone know why this is happening? I'm new to Spring Batch and just can't get my hands around the issue.
有谁知道为什么会这样?我是 Spring Batch 的新手,只是无法解决这个问题。
Thanks /w
谢谢/w
采纳答案by Luca Basso Ricci
The problem is that you marked your reader as scope="prototype"
. It should be scope="step"
.
问题是您将阅读器标记为scope="prototype"
. 应该是scope="step"
。
In Spring-batch there are only two scopes: singleton
(the default) and step
.
在 Spring-batch 中只有两个作用域:(singleton
默认)和step
.
From the javadoc:
从javadoc:
StepScope:
Scope for step context. Objects in this scope use the Spring container as an object factory, so there is only one instance of such a bean per executing step. All objects in this scope are (no need to decorate the bean definitions).
StepScope:
步骤上下文的范围。此范围内的对象使用 Spring 容器作为对象工厂,因此每个执行步骤只有一个此类 bean 的实例。此范围内的所有对象都是(无需修饰 bean 定义)。
and
和
Using a scope of Step is required in order to use late binding since the bean cannot actually be instantiated until the Step starts, which allows the attributes to be found.
为了使用后期绑定,需要使用 Step 的范围,因为在 Step 开始之前无法实际实例化 bean,这允许找到属性。
During the Spring context startup look at your log and you will see this line:
在 Spring 上下文启动期间查看您的日志,您将看到以下行:
INFO: Done executing SQL script from class path resource [org/springframework/batch/core/schema-hsqldb.sql] in 9 ms.
Reading data list [doc1.xkbml, doc2.xkbml, doc3.xkbml]
信息:在 9 毫秒内完成从类路径资源 [org/springframework/batch/core/schema-hsqldb.sql] 执行 SQL 脚本。
读取数据列表【doc1.xkbml、doc2.xkbml、doc3.xkbml】
as you can see your reader has already been created and managed as a singleton; dynamic beans in spring-batch context should be managed with the special step
scope so that Spring will create a fresh copy of the bean every time a step is executed.
如您所见,您的阅读器已经作为单例创建和管理;spring-batch 上下文中的动态 bean 应该使用特殊step
范围进行管理,以便 Spring 每次执行步骤时都会创建 bean 的新副本。
In your reader, ListItemReader.read()
is written as:
在您的阅读器中,ListItemReader.read()
写为:
public T read() {
if (!list.isEmpty()) {
return list.remove(0);
}
return null;
}
In each read items are removed from original list! The reader is constructed once and, on second job execution, the list is empty!
在每个阅读项目从原始列表中删除!读取器被构造一次,在第二次作业执行时,列表是空的!
回答by AmineM
Just an additional information: you can also use JavaConfig instead of the xml config file, and annotate the reader bean declaration with @StepConfig.
只是一个附加信息:您还可以使用 JavaConfig 代替 xml 配置文件,并使用 @StepConfig 注释读取器 bean 声明。
ex:
前任:
@Configuration
@EnableBatchProcessing
public class MyConfig {
...
@Bean
@StepScope
public ItemReader<HeadingBreakevenAssociation> readerHeadingBreakevenAssociationList(){
ItemReader<Person> itemReader = new ListItemReader<Person>(myList);
return itemReader;
}
}