317 lines
8.9 KiB
Plaintext
317 lines
8.9 KiB
Plaintext
[[configuringAJob]]
|
|
= Configuring a Job
|
|
|
|
There are multiple implementations of the xref:job.adoc[`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:
|
|
|
|
[tabs]
|
|
====
|
|
Java::
|
|
+
|
|
[source, java]
|
|
----
|
|
@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 xref:job/java-config.adoc[`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`).
|
|
|
|
XML::
|
|
+
|
|
There are multiple implementations of the xref:job.adoc[`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`:
|
|
+
|
|
[source, xml]
|
|
----
|
|
<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 xref:step.adoc[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:
|
|
+
|
|
[source, xml]
|
|
----
|
|
<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]]
|
|
== 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`.
|
|
|
|
[tabs]
|
|
====
|
|
Java::
|
|
+
|
|
The following example shows how to set the `restartable` field to `false` in Java:
|
|
+
|
|
.Java Configuration
|
|
[source, java]
|
|
----
|
|
@Bean
|
|
public Job footballJob(JobRepository jobRepository) {
|
|
return new JobBuilder("footballJob", jobRepository)
|
|
.preventRestart()
|
|
...
|
|
.build();
|
|
}
|
|
----
|
|
|
|
XML::
|
|
+
|
|
The following example shows how to set the `restartable` field to `false` in XML:
|
|
+
|
|
.XML Configuration
|
|
[source, 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:
|
|
|
|
[source, java]
|
|
----
|
|
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`.
|
|
|
|
[[interceptingJobExecution]]
|
|
== 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:
|
|
|
|
[source, java]
|
|
----
|
|
public interface JobExecutionListener {
|
|
|
|
void beforeJob(JobExecution jobExecution);
|
|
|
|
void afterJob(JobExecution jobExecution);
|
|
}
|
|
----
|
|
|
|
You can add `JobListeners` to a `SimpleJob` by setting listeners on the job.
|
|
|
|
|
|
[tabs]
|
|
====
|
|
Java::
|
|
+
|
|
The following example shows how to add a listener method to a Java job definition:
|
|
+
|
|
.Java Configuration
|
|
[source, java]
|
|
----
|
|
@Bean
|
|
public Job footballJob(JobRepository jobRepository) {
|
|
return new JobBuilder("footballJob", jobRepository)
|
|
.listener(sampleListener())
|
|
...
|
|
.build();
|
|
}
|
|
----
|
|
|
|
XML::
|
|
+
|
|
The following example shows how to add a listener element to an XML job definition:
|
|
+
|
|
.XML Configuration
|
|
[source, xml]
|
|
----
|
|
<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`:
|
|
|
|
[source, java]
|
|
----
|
|
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`
|
|
|
|
[[inheritingFromAParentJob]]
|
|
[role="xmlContent"]
|
|
[[inheriting-from-a-parent-job]]
|
|
== Inheriting from a Parent Job
|
|
|
|
ifdef::backend-pdf[]
|
|
This section applies only to XML based configuration, as Java configuration provides better
|
|
reuse capabilities.
|
|
endif::backend-pdf[]
|
|
|
|
[role="xmlContent"]
|
|
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.
|
|
|
|
[role="xmlContent"]
|
|
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`).
|
|
|
|
[source, xml]
|
|
----
|
|
<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>
|
|
----
|
|
|
|
[role="xmlContent"]
|
|
See the section on xref:step/chunk-oriented-processing/inheriting-from-parent.adoc[Inheriting from a Parent Step]
|
|
for more detailed information.
|
|
|
|
[[jobparametersvalidator]]
|
|
== 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.
|
|
|
|
|
|
[tabs]
|
|
====
|
|
Java::
|
|
+
|
|
The configuration of a validator is supported through the Java builders:
|
|
+
|
|
[source, java]
|
|
----
|
|
@Bean
|
|
public Job job1(JobRepository jobRepository) {
|
|
return new JobBuilder("job1", jobRepository)
|
|
.validator(parametersValidator())
|
|
...
|
|
.build();
|
|
}
|
|
----
|
|
|
|
XML::
|
|
+
|
|
The configuration of a validator is supported through the XML namespace through a child
|
|
element of the job, as the following example shows:
|
|
+
|
|
[source, xml]
|
|
----
|
|
<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.
|
|
|
|
====
|
|
|