What is a JobExecutionListener in Spring Batch, and when do its callbacks run?
answer
- beforeJob / afterJob
- afterJob runs even on FAILED
- JobExecution -> BatchStatus/ExitStatus
- JobBuilder.listener(...)
- @BeforeJob / @AfterJob annotation form
basics
~10 sA JobExecutionListener lets you run code around a job. beforeJob runs before the job starts; afterJob runs once the job finishes, whether it succeeded or failed. You register it on the job builder.
solid answer
~30 sJobExecutionListener is a lifecycle hook with two callbacks: beforeJob(JobExecution) runs once before any step starts, and afterJob(JobExecution) runs once after the job completes. Crucially afterJob runs regardless of outcome — COMPLETED, FAILED, or STOPPED — so it's the right place for cleanup, notifications, or inspecting the final BatchStatus/ExitStatus. You register it with JobBuilder.listener(...). You can either implement the interface (its methods are default methods in Spring Batch 5, so override only what you need) or annotate plain methods with @BeforeJob/@AfterJob. Common uses: sending a completion email, logging start/end timestamps, initializing shared resources, or writing summary metrics from the JobExecution's ExecutionContext.
code
java · 21 linespublic class NotifyingJobListener implements JobExecutionListener {
@Override
public void beforeJob(JobExecution jobExecution) {
jobExecution.getExecutionContext().put("startedAt", System.currentTimeMillis());
}
@Override
public void afterJob(JobExecution jobExecution) {
// Runs on success AND failure
if (jobExecution.getStatus() == BatchStatus.FAILED) {
// send alert
}
}
}
// Registration
Job job = new JobBuilder("reportJob", jobRepository)
.listener(new NotifyingJobListener())
.start(step1)
.build();go deeper
Know the two callbacks and that afterJob runs on success or failure.
Know both registration styles and that JobExecution carries BatchStatus/ExitStatus and an ExecutionContext.
Discuss idempotent cleanup, seeding vs reading the job ExecutionContext, and behavior when beforeJob throws.
Frame it as the outermost of Batch's nested listener scopes and where job-level observability/metrics and resource lifecycles belong.
## What it is Spring Batch models a **Job** as a container of one or more **Steps**. A `JobExecutionListener` is a lifecycle hook that lets your code observe the job as a whole, outside the steps. It has two callbacks: - `void beforeJob(JobExecution jobExecution)` — invoked once, before the first step runs. - `void afterJob(JobExecution jobExecution)` — invoked once, after the last step finishes. Both receive the `JobExecution`, the runtime object describing this run: its `BatchStatus` (COMPLETED / FAILED / STOPPED / etc.), its `ExitStatus`, start/end times, the list of `StepExecution`s, and a job-level `ExecutionContext` (a key/value bag persisted in the job repository). ## Key semantic: afterJob always runs `afterJob` runs **whether the job succeeded or failed** (as long as the job actually started). That makes it the canonical place for cleanup and end-of-job reporting. You typically branch on status: ```java if (jobExecution.getStatus() == BatchStatus.FAILED) { /* alert */ } ``` ## Two ways to write one 1. **Implement the interface.** In Spring Batch 5 the methods are `default`, so you override only the one you care about. 2. **Annotation form.** Put `@BeforeJob` / `@AfterJob` on plain methods of any bean and register that bean; Spring wraps it via `JobListenerFactoryBean`. The annotated method may take a `JobExecution` parameter or no parameter. ## Registration ```java new JobBuilder("myJob", jobRepository) .listener(myJobListener) .start(step1) .build(); ``` ## When to use - Send a start/finish notification or email. - Log or export job-level metrics (durations, counts). - Seed the job `ExecutionContext` before steps, or read aggregated results after. - Acquire/release a resource that spans the whole job. ## Gotchas - Don't put per-record logic here — it fires once per job, not per item; item/step listeners exist for finer scopes. - `beforeJob` is not called if the job fails to launch (e.g., validation of `JobParameters` fails before execution). Once a `JobExecution` exists and starts, both callbacks fire. - Exceptions thrown from `beforeJob` fail the job before any step runs.
- Does afterJob run if the job fails halfway through a step?Yes. As long as the job started, afterJob is always invoked with the final JobExecution — you inspect getStatus()/getExitStatus() to see it FAILED. It only wouldn't run if the job never launched (e.g., pre-launch parameter validation failure).
- How would you use the annotation form instead of implementing the interface?Put @BeforeJob and/or @AfterJob on plain methods of a bean (optionally taking a JobExecution parameter) and pass that bean to JobBuilder.listener(...). Spring wraps it via JobListenerFactoryBean so no interface is needed.
saying these in an interview costs you the question
- Claiming afterJob only runs on success
- Thinking beforeJob/afterJob fire per step or per item
- Confusing JobExecutionListener with StepExecutionListener scope