Configuring a Job
There are multiple implementations of the Job
interface. However,
these implementations are abstracted behind either the provided builders (for Java configuration) or the XML
namespace (for XML-based configuration). The following example shows both Java and XML configuration:
-
Java
-
XML
@Bean
public Job footballJob(JobRepository jobRepository) {
return new JobBuilder("footballJob", jobRepository)
.start(playerLoad())
.next(gameLoad())
.next(playerSummarization())
.build();
}
A Job
(and, typically, any Step
within it) requires a JobRepository
. The
configuration of the JobRepository
is handled through the Java Configuration
.
The preceding example illustrates a Job
that consists of three Step
instances. The job related
builders can also contain other elements that help with parallelization (Split
),
declarative flow control (Decision
), and externalization of flow definitions (Flow
).
There are multiple implementations of the Job
interface. However, the namespace abstracts away the differences in configuration. It has
only three required dependencies: a name, JobRepository
, and a list of Step
instances.
The following example creates a footballJob
:
<job id="footballJob">
<step id="playerload" parent="s1" next="gameLoad"/>
<step id="gameLoad" parent="s2" next="playerSummarization"/>
<step id="playerSummarization" parent="s3"/>
</job>
The preceding examples uses a parent bean definition to create the steps.
See the section on step configuration
for more options when declaring specific step details inline. The XML namespace
defaults to referencing a repository with an id
of jobRepository
, which
is a sensible default. However, you can explicitly override this default:
<job id="footballJob" job-repository="specialRepository">
<step id="playerload" parent="s1" next="gameLoad"/>
<step id="gameLoad" parent="s3" next="playerSummarization"/>
<step id="playerSummarization" parent="s3"/>
</job>
In addition to steps, a job configuration can contain other elements
that help with parallelization (<split>
),
declarative flow control (<decision>
), and
externalization of flow definitions
(<flow/>
).
Restartability
One key issue when executing a batch job concerns the behavior of a Job
when it is
restarted. The launching of a Job
is considered to be a “restart” if a JobExecution
already exists for the particular JobInstance
. Ideally, all jobs should be able to start
up where they left off, but there are scenarios where this is not possible.
In this scenario, it is entirely up to the developer to ensure that a new JobInstance
is created.
However, Spring Batch does provide some help. If a Job
should never be
restarted but should always be run as part of a new JobInstance
, you can set the
restartable property to false
.
-
Java
-
XML
The following example shows how to set the restartable
field to false
in Java:
@Bean
public Job footballJob(JobRepository jobRepository) {
return new JobBuilder("footballJob", jobRepository)
.preventRestart()
...
.build();
}
The following example shows how to set the restartable
field to false
in XML:
<job id="footballJob" restartable="false">
...
</job>
To phrase it another way, setting restartable
to false
means “this
Job
does not support being started again”. Restarting a Job
that is not
restartable causes a JobRestartException
to
be thrown.
The following Junit code causes the exception to be thrown:
Job job = new SimpleJob();
job.setRestartable(false);
JobParameters jobParameters = new JobParameters();
JobExecution firstExecution = jobRepository.createJobExecution(job, jobParameters);
jobRepository.saveOrUpdate(firstExecution);
try {
jobRepository.createJobExecution(job, jobParameters);
fail();
}
catch (JobRestartException e) {
// expected
}
The first attempt to create a
JobExecution
for a non-restartable
job causes no issues. However, the second
attempt throws a JobRestartException
.
Intercepting Job Execution
During the course of the execution of a
Job
, it may be useful to be notified of various
events in its lifecycle so that custom code can be run.
SimpleJob
allows for this by calling a
JobListener
at the appropriate time:
public interface JobExecutionListener {
void beforeJob(JobExecution jobExecution);
void afterJob(JobExecution jobExecution);
}
You can add JobListeners
to a SimpleJob
by setting listeners on the job.
-
Java
-
XML
The following example shows how to add a listener method to a Java job definition:
@Bean
public Job footballJob(JobRepository jobRepository) {
return new JobBuilder("footballJob", jobRepository)
.listener(sampleListener())
...
.build();
}
The following example shows how to add a listener element to an XML job definition:
<job id="footballJob">
<step id="playerload" parent="s1" next="gameLoad"/>
<step id="gameLoad" parent="s2" next="playerSummarization"/>
<step id="playerSummarization" parent="s3"/>
<listeners>
<listener ref="sampleListener"/>
</listeners>
</job>
Note that the afterJob
method is called regardless of the success or
failure of the Job
. If you need to determine success or failure, you can get that information
from the JobExecution
:
public void afterJob(JobExecution jobExecution){
if (jobExecution.getStatus() == BatchStatus.COMPLETED ) {
//job success
}
else if (jobExecution.getStatus() == BatchStatus.FAILED) {
//job failure
}
}
The annotations corresponding to this interface are:
-
@BeforeJob
-
@AfterJob
Inheriting from a Parent Job
If a group of Jobs share similar but not
identical configurations, it may help to define a “parent”
Job
from which the concrete
Job
instances can inherit properties. Similar to class
inheritance in Java, a “child” Job
combines
its elements and attributes with the parent’s.
In the following example, baseJob
is an abstract
Job
definition that defines only a list of
listeners. The Job
(job1
) is a concrete
definition that inherits the list of listeners from baseJob
and merges
it with its own list of listeners to produce a
Job
with two listeners and one
Step
(step1
).
<job id="baseJob" abstract="true">
<listeners>
<listener ref="listenerOne"/>
</listeners>
</job>
<job id="job1" parent="baseJob">
<step id="step1" parent="standaloneStep"/>
<listeners merge="true">
<listener ref="listenerTwo"/>
</listeners>
</job>
See the section on Inheriting from a Parent Step for more detailed information.
JobParametersValidator
A job declared in the XML namespace or using any subclass of
AbstractJob
can optionally declare a validator for the job parameters at
runtime. This is useful when, for instance, you need to assert that a job
is started with all its mandatory parameters. There is a
DefaultJobParametersValidator
that you can use to constrain combinations
of simple mandatory and optional parameters. For more complex
constraints, you can implement the interface yourself.
-
Java
-
XML
The configuration of a validator is supported through the Java builders:
@Bean
public Job job1(JobRepository jobRepository) {
return new JobBuilder("job1", jobRepository)
.validator(parametersValidator())
...
.build();
}
The configuration of a validator is supported through the XML namespace through a child element of the job, as the following example shows:
<job id="job1" parent="baseJob3">
<step id="step1" parent="standaloneStep"/>
<validator ref="parametersValidator"/>
</job>
You can specify the validator as a reference (as shown earlier) or as a nested bean
definition in the beans
namespace.