JobExecutionListener in Spring Batch: beforeJob & afterJob Explained

JobExecutionListener in Spring Batch

If you're working with Spring Batch, you’ve probably heard of JobExecutionListener. It’s one of the handiest tools when it comes to executing logic before or after a batch job runs.

In this guide, we’ll deep dive into how you can use beforeJob() and afterJob() with Spring Boot, why they're useful, and walk through a real example to bring it all together.

What Is JobExecutionListener?

In Spring Batch, JobExecutionListener is an interface that allows you to run custom code:

  • Before the job starts (beforeJob)
  • After the job finishes (afterJob)

public interface JobExecutionListener {
    void beforeJob(JobExecution jobExecution);
    void afterJob(JobExecution jobExecution);
}

  

When Should You Use It?

Common use cases:

  • Logging start/end timestamps
  • Initializing or cleaning up resources
  • Validating preconditions
  • Sending notifications
  • Writing summary reports

Setting Up Spring Batch with Job Listener

1. Add Spring Batch Dependencies


<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-batch</artifactId>
</dependency>

  

2. Create the Job Listener


@Component
public class MyJobListener implements JobExecutionListener {

    @Override
    public void beforeJob(JobExecution jobExecution) {
        System.out.println(">>> Job is starting: " + jobExecution.getJobInstance().getJobName());
        jobExecution.getExecutionContext().putString("startTime", LocalDateTime.now().toString());
    }

    @Override
    public void afterJob(JobExecution jobExecution) {
        System.out.println(">>> Job has finished: " + jobExecution.getStatus());
        String startTime = jobExecution.getExecutionContext().getString("startTime");
        System.out.println(">>> Started at: " + startTime);
        System.out.println(">>> Ended at: " + LocalDateTime.now());
    }
}

  

3. Define a Sample Job and Step

  
@Configuration
public class SpringBatchConfig {

    @Autowired
    private MyJobListener myJobListener;

    @Autowired
    private JobRepository repository;

    @Autowired
    private PlatformTransactionManager platformTransactionManager;

    @Bean
    public Job sampleJob() {
        return new JobBuilder("sample-job",repository).incrementer(new RunIdIncrementer())
                .listener(myJobListener)
                .start(sampleStep())
                .build();
    }

    @Bean
    public Step sampleStep() {
        return new StepBuilder("sample-step",repository)
                .tasklet((contribution, chunkContext) -> {
                    System.out.println("Executing step logic");
                    return RepeatStatus.FINISHED;
                },platformTransactionManager).build();
    }
}

  

Output Example


>>> Job is starting: sampleJob
>>> Executing step logic...
>>> Job has finished: COMPLETED
>>> Started at: 2025-04-21T14:30:12
>>> Ended at: 2025-04-21T14:30:14

  

Pro Tips

  • You can also inject services into your listener for logging, email, DB access, etc.
  • Use ExecutionContext to pass data between beforeJob and afterJob.

Conclusion

Using JobExecutionListener is a clean and powerful way to hook into your Spring Batch job’s lifecycle. Whether you're building monitoring tools, setting up pre-conditions, or logging analytics — these hooks give you all the control you need.