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

Как мы можем обмениваться данными между различными этапами задания в Spring Batch?

Копаясь в Spring Batch, я хотел бы знать, как мы можем обмениваться данными между разными шагами Job?

Можем ли мы использовать JobRepository для этого? Если да, как мы можем это сделать?

Есть ли другой способ выполнения/достижения того же?

4b9b3361

Ответ 1

репозиторий заданий используется косвенно для передачи данных между этапами (Jean-Philippe прав, что лучший способ сделать это - поместить данные в StepExecutionContext, а затем использовать условно названный ExecutionContextPromotionListener, чтобы продвигать клавиши контекста выполнения шага в JobExecutionContext.

Полезно отметить, что есть слушатель для продвижения ключей JobParameter к StepExecutionContext (еще более длинно названный JobParameterExecutionContextCopyListener); вы обнаружите, что используете их много, если ваши шаги работы не полностью независимы друг от друга.

В противном случае вы оставите передачу данных между шагами, используя еще более сложные схемы, такие как JMS-очереди или (запрещающие запрет) жесткие файлы.

Что касается размера данных, передаваемых в контексте, я бы также предположил, что вы держите его маленьким (но у меня нет каких-либо особенностей в

Ответ 2

С шага вы можете поместить данные в StepExecutionContext. Затем с помощью слушателя вы можете продвигать данные с StepExecutionContext на JobExecutionContext.

Этот JobExecutionContext доступен на всех следующих шагах.

Будьте внимательны: данные должны быть короткими. Эти контексты сохраняются в JobRepository путем сериализации и длина ограничена (2500 символов, если я хорошо помню).

Таким образом, эти контексты хороши для совместного использования строк или простых значений, но не для совместного использования коллекций или огромного количества данных.

Обмен огромными объемами данных не является философией Spring Batch. Spring Пакет - это набор различных действий, а не огромный блок обработки бизнеса.

Ответ 3

Я бы сказал, что у вас есть 3 варианта:

  • Используйте StepContext и продвигайте его до JobContext, и у вас есть доступ к нему с каждого шага, вы должны, как указано, соблюдать ограничение по размеру
  • Создайте @JobScope bean и добавьте данные к этому bean, @Autowire там, где это необходимо, и используйте его (недостатком является то, что это структура в памяти и если работа завершается, данные теряются, migh вызывает проблемы с перезапуск)
  • У нас были большие массивы данных, которые нужно обрабатывать на разных этапах (прочитайте каждую строку в csv и напишите в БД, прочитайте из БД, агрегируйте и отправьте в API), поэтому мы решили моделировать данные в новой таблице в том же БД, что и spring пакетные мета-таблицы, сохраняйте ids в JobContext и получайте доступ, когда это необходимо, и удалите эту временную таблицу, когда задание завершится успешно.

Ответ 4

Вы можете использовать Java Bean Object

  • Выполните один шаг
  • Сохранять результат в объекте Java
  • Следующий шаг будет ссылаться на один и тот же объект java, чтобы получить результат, сохраненный на шаге 1

Таким образом, вы можете хранить огромную коллекцию данных, если хотите

Ответ 5

Вот что я сделал, чтобы сохранить объект, доступный через шаги.

  • Создал прослушиватель для установки объекта в контексте задания
@Component("myJobListener")
public class MyJobListener implements JobExecutionListener {

    public void beforeJob(JobExecution jobExecution) {

        String myValue = someService.getValue();
        jobExecution.getExecutionContext().putString("MY_VALUE", myValue);
    }
}
  • Определить слушателя в контексте задания
<listeners>
         <listener ref="myJobListener"/>
</listeners>
  • Потребление значения в шаге с помощью аннотации BeforeStep
@BeforeStep
public void initializeValues(StepExecution stepExecution) {

String value = stepExecution.getJobExecution().getExecutionContext().getString("MY_VALUE");

}

Ответ 6

Мне было поручено запускать пакетное задание по одному. Каждое задание зависит от другого. Первый результат работы должен выполнить последующую программу работы. Я искал, как передавать данные после выполнения задания. Я обнаружил, что этот ExecutionContextPromotionListener вам пригодится.

1) Я добавил bean для "ExecutionContextPromotionListener", как показано ниже

@Bean
public ExecutionContextPromotionListener promotionListener()
{
    ExecutionContextPromotionListener listener = new ExecutionContextPromotionListener();
    listener.setKeys( new String[] { "entityRef" } );
    return listener;
}

2) Затем я привязал одного из слушателей к моим шагам

Step step = builder.faultTolerant()
            .skipPolicy( policy )
            .listener( writer )
            .listener( promotionListener() )
            .listener( skiplistener )
            .stream( skiplistener )
            .build();

3) Я добавил stepExecution как ссылку в моей реализации сценария Writer и занесен в Beforestep

@BeforeStep
public void saveStepExecution( StepExecution stepExecution )
{
    this.stepExecution = stepExecution;
}   

4) в конце моего этапа записи я заполнил значения в stepexecution как клавиши, как показано ниже

lStepContext.put( "entityRef", lMap );

5) После выполнения задания я извлек значения из lExecution.getExecutionContext() и заполняется как ответ на задание.

6) из объекта ответа на задание, я получу значения и заполняю требуемые значения в остальных заданиях.

Вышеприведенный код предназначен для продвижения данных из шагов в ExecutionContext с использованием ExecutionContextPromotionListener. Это можно сделать на любом этапе.

Ответ 7

Используйте `ExecutionContextPromotionListener.

public class YourItemWriter implements ItemWriter<Object> {
private StepExecution stepExecution;
public void write(List<? extends Object> items) throws Exception {
// Some Business Logic

// put your data into stepexecution context
ExecutionContext stepContext = this.stepExecution.getExecutionContext();
stepContext.put("someKey", someObject);
}
@BeforeStep
public void saveStepExecution(Final StepExecution stepExecution) {
this.stepExecution = stepExecution;
}
}

Теперь вам нужно добавить promotionListener на свою работу

@Bean
public Step step1() {
        return stepBuilder
        .get("step1")<Company,Company>  chunk(10)
        .reader(reader()).processor(processor()).writer(writer())
        .listener(promotionListner()).build();
    }

@Bean  public ExecutionContextPromotionListener promotionListner() {       ExecutionContextPromotionListener listner = new ExecutionContextPromotionListener();       listner.setKeys(новый String [] { "someKey" });       listner.setStrict(истина);       return listner;   }

Теперь, на шаге2, получите данные из задания ExecutionContext

public class RetrievingItemWriter implements ItemWriter<Object> {
private Object someObject;
public void write(List<? extends Object> items) throws Exception {
// ...
}
@BeforeStep
public void retrieveInterstepData(StepExecution stepExecution) {
JobExecution jobExecution = stepExecution.getJobExecution();
ExecutionContext jobContext = jobExecution.getExecutionContext();
this.someObject = jobContext.get("someKey");
}
}

Если вы работаете с тасками, используйте команду follwing для получения или установки ExecutionContext

List<YourObject> yourObjects = (List<YourObject>) chunkContent.getStepContext().getJobExecutionContext().get("someKey");