Сохранение в JobExecutionContext из тасклета и доступ к другому тасклету - PullRequest
21 голосов
/ 14 ноября 2011

У меня есть требование, при котором тасклет хранит все файлы в каталогах в виде списка. Размер списка хранится в контексте выполнения задания. Позже к этому счету обращаются из другого тасклета на другом шаге. Как это сделать? Я пытался сохранить в контексте JobExecution, во время выполнения выдает исключение неизменяемой коллекции,

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 в аннотации до шага. Пока не возможно. Пожалуйста, дайте мне знать, как обмениваться данными между двумя тасклетами.

Ответы [ 2 ]

54 голосов
/ 14 ноября 2011

у вас есть как минимум 4 возможности:

  1. используйте ExecutionPromotionListener для передачи данных на будущие шаги
  2. используйте (пружинный) компонент для удержания интерданные шага, например ConcurrentHashMap
    • без дальнейших действий, эти данные не будут доступны для перезапуска
  3. доступа к JobExecutionContext в вашем тасклете, должны использоваться состорожно, это вызовет проблемы с потоками для параллельных шагов
  4. используйте новый jobscope (представлен в пакете пружин 3)

Пример кода для доступа к JobExecution из Tasklet:

  1. установка значения

    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;
        }
    
    }
    
  2. извлечение значения

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

я создал кодпримеры для первых 3 решений в моем репозитории github для spring-batch-examples , см. модуль complex и пакет interstepcommunication

5 голосов
/ 06 февраля 2012

Другой способ - использовать 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;
    }
}

Итак, на этом шаге ваш боб является тасклетом и слушателем, как показано ниже. Вы также должны настроить область вашего шага на «шаг»:

    <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">
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...