2013-08-29 3 views
4

Я пытаюсь создать весеннее пакетное задание с использованием ListItemReader<String>, ItemProcessor<String, String> и ItemWriter<String>.Весенний пакетный список списка товаров обрабатывается только один раз

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 и просто не могу разобраться с проблемой.

Благодаря/ш

ответ

13

Проблема заключается в том, что вы отметили читателя как scope="prototype". Он должен быть scope="step".

В весенней партии есть только две области: singleton (по умолчанию) и step.

От javadoc:

StepScope:
Scope для шага контекста. Объекты в этой области используют контейнер Spring как фабрику объектов, поэтому есть только один экземпляр такого компонента на каждый шаг выполнения. Все объекты в этой области: (не нужно украшать определения компонентов).

и

Использование сферы шаг необходим для того, чтобы использовать позднее связывание, поскольку бин фактически не может быть реализован, пока не начнется Шаг, который позволяет атрибуты должны быть найдены.

В контексте Spring запуска взглянуть на ваш журнал, и вы увидите строку:

INFO: Готово выполнения SQL скрипт из пути класса ресурса [орг/springframework/партии/ядро ​​/ схе- hsqldb.sql] за 9 мс.
Список данных для чтения [doc1.xkbml, doc2.xkbml, doc3.xkbml]

как вы видите, ваш читатель уже создан и управляется как одноэлементный; динамические компоненты в контексте весеннего пакета должны управляться с помощью специальной области step, чтобы Spring создавала новую копию компонента каждый раз, когда выполняется шаг.

В читателя, ListItemReader.read() записывается как:

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

В каждой операции чтения элементы удаляются из исходного списка! Читатель построен один раз, а во втором выполнении задания список пуст!

+2

Спасибо, спасибо, что это именно то, что проблема была. – wsams

+0

Отлично. Можно ли использовать ListItemReader в многопоточном шаге для одновременного обработки элементов в списке? Будет ли перезагружать работу? – vishal

+1

Nope. ListItemReader не перезапускается, поскольку он не поддерживает ItemStrem; этот класс (от javadoc) является ** 'Полезно для тестирования' ** –

4

Только дополнительная информация: вы также можете использовать JavaConfig вместо файла конфигурации xml и аннотировать декларацию bean-компонента читателя с помощью @StepConfig.

например:

@Configuration 
@EnableBatchProcessing 
public class MyConfig { 
... 

    @Bean 
    @StepScope 
    public ItemReader<HeadingBreakevenAssociation> readerHeadingBreakevenAssociationList(){ 
     ItemReader<Person> itemReader = new ListItemReader<Person>(myList); 

      return itemReader; 
    } 

} 
+0

Это сработало для меня. Благодаря! – jsmtslch

Смежные вопросы