Подтвердить что ты не робот

Сохранение в 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. По всей вероятности, не сообщайте мне, как делиться данными между двумя тасками.

4b9b3361

Ответ 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">