Сохранение в JobExecutionContext из тасклета и доступ к нему в другом таскеле
У меня есть требование, в котором находится тасклет, сохраняет все файлы в каталогах в arraylist. Размер списка сохраняется в контексте выполнения задания. Позже этот счетчик получает доступ к другому шагу на другом шаге. Как это сделать. Я попытался сохранить в контексте выполнения работы, во время выполнения выбрасывает немодифицируемое исключение коллекции,
public RepeatStatus execute(StepContribution arg0, ChunkContext arg1)
throws Exception {
StepContext stepContext = arg1.getStepContext();
StepExecution stepExecution = stepContext.getStepExecution();
JobExecution jobExecution = stepExecution.getJobExecution();
ExecutionContext jobContext = jobExecution.getExecutionContext();
jobContext.put("FILE_COUNT",150000);
также сохранил ссылку на stepexection в аннотации beforestep. По всей вероятности, не сообщайте мне, как делиться данными между двумя тасками.
Ответы
Ответ 1
у вас есть как минимум 4 возможности:
- использовать ExecutionPromotionListener для передать данные в будущие шаги
- используйте (spring) bean для хранения данных между шагами, например. Консоль
- без дальнейших действий эти данные не будут доступны для повторного запуска
- доступ к JobExecutionContext в вашем таскете, должен использоваться с осторожностью, вызовет проблемы с потоком для параллельных шагов.
- используйте новый тип задания (представлен с spring пакетом 3)
Пример кода для доступа к JobExecution из Tasklet:
-
установка значения
public class ChangingJobExecutionContextTasklet implements Tasklet {
/** {@inheritDoc} */
@Override
public RepeatStatus execute(StepContribution contribution, ChunkContext chunkContext) throws Exception {
// set variable in JobExecutionContext
chunkContext
.getStepContext()
.getStepExecution()
.getJobExecution()
.getExecutionContext()
.put("value", "foo");
// exit the step
return RepeatStatus.FINISHED;
}
}
-
извлечение значения
public class ReadingJobExecutionContextTasklet implements Tasklet {
private static final Logger LOG = LoggerFactory.getLogger(ChangingJobExecutionContextTasklet.class);
/** {@inheritDoc} */
@Override
public RepeatStatus execute(StepContribution contribution, ChunkContext chunkContext) throws Exception {
// pull variable from JobExecutionContext
String value = (String) chunkContext
.getStepContext()
.getStepExecution()
.getJobExecution()
.getExecutionContext()
.get("value");
LOG.debug("Found value in JobExecutionContext:" + value);
// exit the step
return RepeatStatus.FINISHED;
}
}
я создал примеры кода для первых трех решений в my spring -batch-examples github-репозиторий, см. комплекс модулей и пакетное межсетевое взаимодействие
Ответ 2
Другой способ - использовать StepExecutionListener
, который вызывается после выполнения шага.
Ваш тасклет может реализовать его и обмениваться локальным атрибутом.
public class ReadingJobExecutionContextTasklet implements Tasklet, StepExecutionListener {
private String value;
@Override
public ExitStatus afterStep(StepExecution stepExecution) {
ExecutionContext jobExecutionContext = stepExecution.getJobExecution().getExecutionContext();
jobExecutionContext.put("key", value);
//Return null to leave the old value unchanged.
return null;
}
}
Итак, на шаге ваш bean - это тасклет и слушатель, как показано ниже.
Вы также должны настроить область действия шага "step":
<batch:step id="myStep" next="importFileStep">
<batch:tasklet>
<ref bean="myTasklet"/>
<batch:listeners>
<batch:listener ref="myTasklet"/>
</batch:listeners>
</batch:tasklet>
</batch:step>
<bean id="myTasklet" class="ReadingJobExecutionContextTasklet" scope="step">