Копаясь в Spring Batch, я хотел бы знать, как мы можем обмениваться данными между разными шагами Job?
Можем ли мы использовать JobRepository для этого? Если да, как мы можем это сделать?
Есть ли другой способ выполнения/достижения того же?
Копаясь в Spring Batch, я хотел бы знать, как мы можем обмениваться данными между разными шагами Job?
Можем ли мы использовать JobRepository для этого? Если да, как мы можем это сделать?
Есть ли другой способ выполнения/достижения того же?
репозиторий заданий используется косвенно для передачи данных между этапами (Jean-Philippe прав, что лучший способ сделать это - поместить данные в StepExecutionContext
, а затем использовать условно названный ExecutionContextPromotionListener
, чтобы продвигать клавиши контекста выполнения шага в JobExecutionContext
.
Полезно отметить, что есть слушатель для продвижения ключей JobParameter
к StepExecutionContext
(еще более длинно названный JobParameterExecutionContextCopyListener
); вы обнаружите, что используете их много, если ваши шаги работы не полностью независимы друг от друга.
В противном случае вы оставите передачу данных между шагами, используя еще более сложные схемы, такие как JMS-очереди или (запрещающие запрет) жесткие файлы.
Что касается размера данных, передаваемых в контексте, я бы также предположил, что вы держите его маленьким (но у меня нет каких-либо особенностей в
С шага вы можете поместить данные в StepExecutionContext
.
Затем с помощью слушателя вы можете продвигать данные с StepExecutionContext
на JobExecutionContext
.
Этот JobExecutionContext
доступен на всех следующих шагах.
Будьте внимательны: данные должны быть короткими.
Эти контексты сохраняются в JobRepository
путем сериализации и длина ограничена (2500 символов, если я хорошо помню).
Таким образом, эти контексты хороши для совместного использования строк или простых значений, но не для совместного использования коллекций или огромного количества данных.
Обмен огромными объемами данных не является философией Spring Batch. Spring Пакет - это набор различных действий, а не огромный блок обработки бизнеса.
Я бы сказал, что у вас есть 3 варианта:
StepContext
и продвигайте его до JobContext
, и у вас есть доступ к нему с каждого шага, вы должны, как указано, соблюдать ограничение по размеру@JobScope
bean и добавьте данные к этому bean, @Autowire
там, где это необходимо, и используйте его (недостатком является то, что это структура в памяти и если работа завершается, данные теряются, migh вызывает проблемы с перезапуск)ids
в JobContext
и получайте доступ, когда это необходимо, и удалите эту временную таблицу, когда задание завершится успешно.Вы можете использовать Java Bean Object
Таким образом, вы можете хранить огромную коллекцию данных, если хотите
Вот что я сделал, чтобы сохранить объект, доступный через шаги.
@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
public void initializeValues(StepExecution stepExecution) {
String value = stepExecution.getJobExecution().getExecutionContext().getString("MY_VALUE");
}
Мне было поручено запускать пакетное задание по одному. Каждое задание зависит от другого. Первый результат работы должен выполнить последующую программу работы. Я искал, как передавать данные после выполнения задания. Я обнаружил, что этот 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. Это можно сделать на любом этапе.
Используйте `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");