Spring ItemReader batch list is processed only once

I am trying to create a Spring batch job using ListItemReader<String> , ItemProcessor<String, String> and ItemWriter<String> .

XML is as follows:

 <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); } } 

Work starts as follows, but on a schedule every 10 seconds.

 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 that it reads, processes, and writes each of the three elements 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] 

Since this sourceJob is on the scheduled timer, every 10 seconds I expected to see that this list has been processed, but instead I see on all subsequent launches.

 Reading data null 

Does anyone know why this is happening? I am new to Spring Batch and just cant deal with the problem.

Thanks / w

+4
source share
2 answers

The problem is that you marked the reader as scope="prototype" . This should be scope="step" .

There are only two areas in Spring-batch: singleton (default) and step .

From javadoc :

StepScope :
The scope of the context. The objects in this area use the Spring container as a factory object, so there is only one instance of such a bean for each step of execution. All objects in this area (no need to decorate bean definitions).

and

Using the scope of the step is required to use late binding, since the bean cannot actually be created before the start of the step that allows you to find attributes.

When starting the Spring context menu, review your log and you will see this line:

INFO: Executing an SQL script from a resource of the class path [org / springframework / batch / core / schema-hsqldb.sql] in 9 ms.
Reading a data list [doc1.xkbml, doc2.xkbml, doc3.xkbml]

since you can see that your reader is already created and managed as a singleton; dynamic beans in the Spring-batch context must be controlled using the special step scope so that Spring creates a new copy of the bean every time the step is executed.

In your reader, ListItemReader.read() written as:

 public T read() { if (!list.isEmpty()) { return list.remove(0); } return null; } 

In each of the read items are deleted from the original list! The reader is created once, and when completing the second task, the list is empty!

+13
source

Just extra info: you can also use JavaConfig instead of the xml configuration file and annotate the bean reader declaration with @StepConfig.

ex:

 @Configuration @EnableBatchProcessing public class MyConfig { ... @Bean @StepScope public ItemReader<HeadingBreakevenAssociation> readerHeadingBreakevenAssociationList(){ ItemReader<Person> itemReader = new ListItemReader<Person>(myList); return itemReader; } } 
+4
source

Source: https://habr.com/ru/post/1499687/


All Articles