skip to content

What is Spring Batch's JobOperator, and how does it differ from JobLauncher?

level: juniorimportance: must knowfreq 50%

answer

  1. Operator = admin facade, Launcher = runner
  2. Simple types: names + ids + Properties
  3. SimpleJobOperator needs Launcher+Registry+Repository+Explorer
  4. Job must be in JobRegistry (resolve by name)
  5. start/stop/restart/abandon/startNextInstance

basics

~10 s

JobOperator is an operations-facing facade for controlling jobs — start, stop, restart, and abandon executions using simple types like job names and execution ids. JobLauncher just runs a Job you already have wired.

solid answer

~40 s

JobLauncher has a single job: take a Job object plus JobParameters and run it, returning a JobExecution. JobOperator is a higher-level, operations-oriented facade meant for administrators, CLIs, JMX, or a web console. It works with simple types — String job names, long execution/instance ids, Properties — so callers don't need Java references to Job or JobParameters. It exposes start(jobName, params), startNextInstance(jobName), restart(executionId), stop(executionId), abandon(executionId), plus read/query methods like getRunningExecutions(jobName), getJobNames(), and getSummary(). Internally SimpleJobOperator delegates the actual running to a JobLauncher and looks jobs up via a JobRegistry, reading metadata through JobRepository/JobExplorer. So JobOperator complements — it doesn't replace — JobLauncher: launcher runs, operator manages the lifecycle around running jobs.

code

java · 16 lines
java
@Service
public class BatchOps {

    private final JobOperator jobOperator; // SimpleJobOperator

    public BatchOps(JobOperator jobOperator) {
        this.jobOperator = jobOperator;
    }

    // Operator-style: by name + Properties, returns execution id
    public Long importFile(String path) throws Exception {
        Properties p = new Properties();
        p.setProperty("inputFile", path);
        return jobOperator.start("importJob", p);
    }
}

go deeper

for a junior

Know it's the ops facade: start/stop/restart by name and id, vs JobLauncher which just runs a Job.

for a middle

Know SimpleJobOperator's four collaborators and that jobs are resolved by name from JobRegistry.

for a senior

Can explain when to reach for operator vs launcher and the String-vs-typed parameter nuance.

for a principal

Positions JobOperator as the boundary for external management tooling (JMX/CLI/console) and knows registry wiring pitfalls.

**The two abstractions.** Spring Batch separates *launching* a job from *operating* jobs. - `JobLauncher` is the minimal runner. Its only method is `JobExecution run(Job job, JobParameters jobParameters)`. You must already hold a `Job` bean and build a typed `JobParameters` object. The default `TaskExecutorJobLauncher` (formerly `SimpleJobLauncher`) runs it synchronously or, if given an async `TaskExecutor`, on another thread. - `JobOperator` is an operations/management facade. It is designed to be driven by things that don't have Java handles to your beans: a command-line launcher, a JMX MBean, an admin web page. Therefore every method speaks in *simple types* — `String` job names, `long` execution and instance ids, `java.util.Properties` for parameters. **Core methods (classic Spring Batch 5.x interface).** - `Long start(String jobName, Properties parameters)` — create and run a brand-new `JobInstance`. - `Long startNextInstance(String jobName)` — run the next instance using the job's `JobParametersIncrementer`. - `Long restart(long executionId)` — re-run a failed/stopped execution of the same instance. - `boolean stop(long executionId)` — request a graceful (cooperative) stop. - `JobExecution abandon(long executionId)` — mark a non-running execution as ABANDONED. - Query side: `Set<Long> getRunningExecutions(String jobName)`, `Set<String> getJobNames()`, `List<Long> getJobInstances(...)`, `getExecutions(long instanceId)`, `String getSummary(long executionId)`, `Map<Long,String> getStepExecutionSummaries(...)`, `String getParameters(long executionId)`. **Implementation and wiring.** The stock implementation is `SimpleJobOperator`. It needs four collaborators: a `JobLauncher` (to actually run), a `JobRegistry` (to resolve a `Job` from a `String` name), a `JobRepository`, and a `JobExplorer` (to read execution metadata). Because it resolves jobs by *name*, your `Job` beans must be registered in the `JobRegistry` — historically via a `JobRegistryBeanPostProcessor` (newer versions use a `JobRegistrySmartInitializingSingleton`). If the registry is empty, `start("myJob", ...)` fails with `NoSuchJobException`. **When to use which.** Use `JobLauncher` inside application code that already owns the `Job` (e.g. a `CommandLineRunner`, a scheduled method, an integration flow). Use `JobOperator` when a human operator or an external tool must manage jobs by name/id — cancel a runaway execution, kick off the next daily run, restart yesterday's failure, or list what's currently running. Note: parameters passed to `JobOperator.start` come in as `String`s (from `Properties`), so type-conversion of parameter values differs subtly from constructing `JobParameters` directly. **Version note.** The signatures above describe the long-stable Spring Batch 5.x `JobOperator`. Spring Batch has continued to evolve this facade in later major versions, but the operational concepts — start, startNextInstance, stop, restart, abandon, list running — are the constant interview target.

  • Which collaborators must a SimpleJobOperator be given?
    A JobLauncher (to run), a JobRegistry (to resolve Job by name), a JobRepository, and a JobExplorer (to read metadata). Missing/empty registry causes NoSuchJobException.
  • Why does JobOperator use Strings and longs instead of Job/JobParameters objects?
    So it can be driven by tools without Java references — JMX MBeans, CLI launchers, admin web consoles — which naturally pass job names and numeric ids.

saying these in an interview costs you the question

  • Saying JobOperator replaces JobLauncher (it delegates to one)
  • Thinking JobOperator takes a Job object rather than a job name
  • Not knowing it needs a JobRegistry to look jobs up by name

context