Configuring a Job
Job
接口有多个实现。然而,这些实现通过提供的构建器(用于 Java 配置)或 XML 命名空间(用于基于 XML 的配置)抽象出来。以下示例显示了 Java 和 XML 配置:
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
-
@Bean public Job footballJob(JobRepository jobRepository) { return new JobBuilder("footballJob", jobRepository) .start(playerLoad()) .next(gameLoad()) .next(playerSummarization()) .build(); }
Job
(通常还有其中的任何 Step
)需要 JobRepository
。JobRepository
的配置通过 Java Configuration
处理。
A Job
(and, typically, any Step
within it) requires a JobRepository
. The
configuration of the JobRepository
is handled through the Java Configuration
.
前面的示例说明了一个由三个 Step
实例组成的 Job
。与作业相关的构建器还可以包含帮助并行化(Split
)、声明式流控制(Decision
)和流定义外化(Flow
)的其他元素。
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
-
Job
接口有多个实现。然而,命名空间抽象了配置中的差异。它只有三个必需的依赖项:name、JobRepository
和Step
实例的列表。以下示例创建一个footballJob
:
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>
前面的示例使用父 bean 定义来创建步骤。有关在行内声明特定步骤详细信息的更多选项,请参阅有关步骤配置的部分。XML 命名空间默认为引用带有 id
为 jobRepository
的存储库,这是一个明智的默认设置。但是,你可以明确覆盖此默认设置:
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>
除步骤外,作业配置还可能包含有助于并行化(<split>
)、声明式流控制(<decision>
)和流定义外部化(<flow/>
)的其他元素。
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
执行批处理作业时一个关键问题在于,当一个“任务”被重新启动时其行为。如果一个 Job 执行已经存在于特定的 Job 实例中,那么启动一个“任务”被认为是一个“重新启动”。理想情况下,所有任务都应该能够从上次中断的地方开始,但是有些情况下这是不可能的。在这个场景中,确保创建一个新的 Job 实例完全取决于开发人员。然而,Spring Batch 确实提供了一些帮助。如果一个“任务”永远不应该被重新启动,而应该始终作为新 Job 实例的一部分运行,你可以将 restartable 属性设置为 false。
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
-
下面的例子展示了如何在 Java 中将
restartable
字段设置为false
:
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();
}
- XML
-
下面的例子展示了如何在 XML 中将
restartable
字段设置为false
:
The following example shows how to set the restartable
field to false
in XML:
<job id="footballJob" restartable="false">
...
</job>
用另一种方式表述,将 restartable
设置为 false
表示“这个任务不支持再次启动”。重新启动一个不可重新启动的“任务”会导致抛出 JobRestartException。下面的 JUnit 代码会导致抛出异常:
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
}
第一次尝试为不可重新启动的任务创建一个 JobExecution 不会造成问题。但是,第二次尝试会抛出 JobRestartException。
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
在执行一个“任务”的过程中,可能会需要获得其生命周期中各个事件的通知,以便运行自定义代码。SimpleJob 通过在适当的时间调用一个 JobListener 来允许这样做:
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);
}
可以通过在作业中设置侦听器来向 SimpleJob 添加 JobListeners。
You can add JobListeners
to a SimpleJob
by setting listeners on the job.
- Java
-
下面的例子展示了如何在 Java 作业定义中添加一个侦听器方法:
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();
}
- XML
-
下面的例子展示了如何在 XML 作业定义中添加一个侦听器元素:
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>
请注意,无论“任务”是否成功或失败,都会调用 afterJob 方法。如果你需要确定成功或失败,你可以从 JobExecution 中获取该信息:
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
如果一组任务共享相似但不完全相同的配置,则定义一个“父级”任务可能会有所帮助,具体任务实例可以从中继承属性。类似于 Java 中的类继承,“子级”任务结合了其元素和属性与父级的元素和属性。
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.
在下面的例子中,baseJob
是一个抽象“任务”定义,仅定义了一个侦听器列表。这个“任务” (job1
) 是一个具体定义,从 baseJob
继承了侦听器列表,并将其与它自己的侦听器列表合并以创建一个具有两个侦听器和一个步骤 (step1
) 的“任务”。
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>
请参阅有关 [继承父步骤,inheritingFromParentStep] 的章节以获取更详细的信息。
See the section on inheritingFromParentStep for more detailed information.
JobParametersValidator
在 XML 名称空间中声明或者使用 AbstractJob
的任何子类的任务可以选择为运行时的任务参数声明一个验证器。举例来说,当需要断言一个任务已经使用其所有必需的参数启动时,这很有用。有一个 DefaultJobParametersValidator,你可以用它来限制简单必需参数和可选参数的组合。对于更复杂的限制,你可以自己实现该接口。
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
-
可以通过 Java 构建器来支持验证器的配置:
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();
}
- XML
-
可以通过 XML 名称空间通过任务的子元素来支持验证器的配置,如下面的例子所示:
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>
你可以将验证器指定为一个引用(如前面所示)或在 beans 名称空间中指定为一个嵌套 bean 定义。
You can specify the validator as a reference (as shown earlier) or as a nested bean
definition in the beans
namespace.