It is often useful to pass information from one step to another. This can be done through the ExecutionContext. The catch is that there are two ExecutionContexts: one at the Step level and one at the Job level. The Step ExecutionContext remains only as long as the step, while the Job ExecutionContext remains through the whole Job. On the other hand, the Step ExecutionContext is updated every time the Step commits a chunk, while the Job ExecutionContext is updated only at the end of each Step.
The consequence of this separation is that all data must be placed in the Step ExecutionContext while the Step is executing. Doing so ensures that the data is stored properly while the Step runs. If data is stored to the Job ExecutionContext, then it is not persisted during Step execution. If the Step fails, that data is lost.
public class SavingItemWriter implements ItemWriter<Object> {
private StepExecution stepExecution;
public void write(List<? extends Object> items) throws Exception {
// ...
ExecutionContext stepContext = this.stepExecution.getExecutionContext();
stepContext.put("someKey", someObject);
}
@BeforeStep
public void saveStepExecution(StepExecution stepExecution) {
this.stepExecution = stepExecution;
}
}
To make the data available to future Steps, it must be “promoted” to the Job ExecutionContext after the step has finished. Spring Batch provides the ExecutionContextPromotionListener for this purpose. The listener must be configured with the keys related to the data in the ExecutionContext that must be promoted. It can also, optionally, be configured with a list of exit code patterns for which the promotion should occur (COMPLETED is the default). As with all listeners, it must be registered on the Step as shown in the following example:
Java Configuration
@Bean
public Job job1() {
return this.jobBuilderFactory.get("job1")
.start(step1())
.next(step1())
.build();
}
@Bean
public Step step1() {
return this.stepBuilderFactory.get("step1")
.<String, String>chunk(10)
.reader(reader())
.writer(savingWriter())
.listener(promotionListener())
.build();
}
@Bean
public ExecutionContextPromotionListener promotionListener() {
ExecutionContextPromotionListener listener = new ExecutionContextPromotionListener();
listener.setKeys(new String[] {"someKey" });
return listener;
}
Finally, the saved values must be retrieved from the Job ExecutionContext, as shown in the following example:
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");
}
}
In similar way, @AfterStep annotated method can be used to read/write the ExecutionContext and can access in future Step.
@AfterStep
public ExitStatus afterStep(StepExecution execution) {
this.stepExecution = stepExecution;
return execution.getExitStatus();
}
I hope you have enjoyed this post and it helped you to Passing Data to Future Steps in Spring Batch. Please like and share and feel free to comment if you have any suggestions or feedback.
Pradeep Mishra
Share post:
It is often useful to pass information from one step to another. This can be done through the
ExecutionContext. The catch is that there are twoExecutionContexts: one at theSteplevel and one at theJoblevel. TheStepExecutionContextremains only as long as the step, while theJobExecutionContextremains through the wholeJob. On the other hand, theStepExecutionContextis updated every time theStepcommits a chunk, while theJobExecutionContextis updated only at the end of eachStep.The consequence of this separation is that all data must be placed in the
StepExecutionContextwhile theStepis executing. Doing so ensures that the data is stored properly while theStepruns. If data is stored to theJobExecutionContext, then it is not persisted duringStepexecution. If theStepfails, that data is lost.public class SavingItemWriter implements ItemWriter<Object> { private StepExecution stepExecution; public void write(List<? extends Object> items) throws Exception { // ... ExecutionContext stepContext = this.stepExecution.getExecutionContext(); stepContext.put("someKey", someObject); } @BeforeStep public void saveStepExecution(StepExecution stepExecution) { this.stepExecution = stepExecution; } }To make the data available to future
Steps, it must be “promoted” to theJobExecutionContextafter the step has finished. Spring Batch provides theExecutionContextPromotionListenerfor this purpose. The listener must be configured with the keys related to the data in theExecutionContextthat must be promoted. It can also, optionally, be configured with a list of exit code patterns for which the promotion should occur (COMPLETEDis the default). As with all listeners, it must be registered on theStepas shown in the following example:Java Configuration
@Bean public Job job1() { return this.jobBuilderFactory.get("job1") .start(step1()) .next(step1()) .build(); } @Bean public Step step1() { return this.stepBuilderFactory.get("step1") .<String, String>chunk(10) .reader(reader()) .writer(savingWriter()) .listener(promotionListener()) .build(); } @Bean public ExecutionContextPromotionListener promotionListener() { ExecutionContextPromotionListener listener = new ExecutionContextPromotionListener(); listener.setKeys(new String[] {"someKey" }); return listener; }Finally, the saved values must be retrieved from the
JobExecutionContext, as shown in the following example: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"); } }In similar way, @AfterStep annotated method can be used to read/write the ExecutionContext and can access in future Step.
@AfterStep public ExitStatus afterStep(StepExecution execution) { this.stepExecution = stepExecution; return execution.getExitStatus(); }I hope you have enjoyed this post and it helped you to Passing Data to Future Steps in Spring Batch. Please like and share and feel free to comment if you have any suggestions or feedback.
Share this:
Like this:
Migrating the project from Java 8 to 17 and Spring Boot 2.x to 3.x
In this blog, I will highlight the changes and challenges that I have faced while doing the migration of services from java 8 to 17 and Spring Boot 2.x to. read more…
Share this:
Like this:
Continue Reading
Build a module with its dependencies in a multi-module Maven project
INTRODUCTION The mechanism in Maven 4 that handles multi-module projects is referred to as the reactor. This part of the Maven core does the following: Module collection starts from one aggregator. read more…
Share this:
Like this:
Continue Reading
Schedule Jobs/Tasks Using Cron Expression in Spring with Example
When we have a requirement to run a task/job repeatedly after a particular time interval, we achieve this functionality by implementing Scheduling. To schedule jobs in the spring boot application to run. read more…
Share this:
Like this:
Continue Reading
Accessing Data with JPA
JPA is a specification which specifies how to access, manage and persist information/data between java objects and relational databases. It provides a standard approach for ORM, Object Relational Mapping. Spring. read more…
Share this:
Like this:
Continue Reading