Running a Job
Batch Processing, Exit Codes, JobExecution, ExitCodeMapper, CommandLine, Web Container, Spring MVC :description: Spring Batch 提供了两种方法来启动批处理作业:从命令行和 Web 容器中。从命令行启动作业需要一个 CommandLineJobRunner,该 runner 加载 ApplicationContext、解析命令行参数、找到作业并使用 JobLauncher 启动作业。从 Web 容器启动作业涉及一个异步 JobLauncher,该 JobLauncher 在 HttpRequest 范围内运行,在控制器中使用 JobLauncher 启动作业,该 JobLauncher 立即返回 JobExecution。
至少,启动一个批处理作业需要两件事:要启动的 Job
和 JobLauncher
。两者都可以包含在同一个上下文或不同的上下文中。例如,如果你从命令行启动作业,则为每个 Job
实例化一个新的 JVM。因此,每个作业都有自己的 JobLauncher
。但是,如果你从 HttpRequest
范围内的 Web 容器内运行,则通常还有一个 JobLauncher
(配置用于异步作业启动),多个请求调用该 JobLauncher
来启动它们的作业。
At a minimum, launching a batch job requires two things: the
Job
to be launched and a
JobLauncher
. Both can be contained within the same
context or different contexts. For example, if you launch jobs from the
command line, a new JVM is instantiated for each Job
. Thus, every
job has its own JobLauncher
. However, if
you run from within a web container that is within the scope of an
HttpRequest
, there is usually one
JobLauncher
(configured for asynchronous job
launching) that multiple requests invoke to launch their jobs.
Running Jobs from the Command Line
如果你想从企业计划程序运行作业,则命令行是主要接口。这是因为大多数计划程序(Quartz 除外,除非使用 NativeJob
)直接与操作系统进程一起工作,主要是用 shell 脚本启动的。除了 shell 脚本之外,还有许多方法可以启动 Java 进程,例如 Perl、Ruby,甚至构建工具,例如 Ant 或 Maven。然而,由于大多数人熟悉 shell 脚本,所以本示例重点关注它们。
If you want to run your jobs from an enterprise
scheduler, the command line is the primary interface. This is because
most schedulers (with the exception of Quartz, unless using
NativeJob
) work directly with operating system
processes, primarily kicked off with shell scripts. There are many ways
to launch a Java process besides a shell script, such as Perl, Ruby, or
even build tools, such as Ant or Maven. However, because most people
are familiar with shell scripts, this example focuses on them.
The CommandLineJobRunner
由于启动作业的脚本必须启动 Java Virtual Machine,因此需要有一个带有 main
方法的类充当主要入口点。Spring Batch 提供了一个实现来实现此目的:CommandLineJobRunner
。请注意,这只是引导应用程序的一种方式。有许多方法可以启动 Java 进程,此类决不应被视为明确的。CommandLineJobRunner
执行四项任务:
Because the script launching the job must kick off a Java
Virtual Machine, there needs to be a class with a main
method to act
as the primary entry point. Spring Batch provides an implementation
that serves this purpose:
CommandLineJobRunner
. Note
that this is just one way to bootstrap your application. There are
many ways to launch a Java process, and this class should in no way be
viewed as definitive. The CommandLineJobRunner
performs four tasks:
-
Load the appropriate
ApplicationContext
. -
Parse command line arguments into
JobParameters
. -
Locate the appropriate job based on arguments.
-
Use the
JobLauncher
provided in the application context to launch the job.
所有这些任务仅使用传入的参数完成。下表描述了必需的参数:
All of these tasks are accomplished with only the arguments passed in. The following table describes the required arguments:
|
The location of the XML file that is used to
create an |
|
The name of the job to be run. |
必须传入这些参数,先输入路径,然后再输入名称。这些之后的所有参数都被视为作业参数,变为一个 JobParameters
对象,并且必须采用 name=value
格式。
These arguments must be passed in, with the path first and the name second. All arguments
after these are considered to be job parameters, are turned into a JobParameters
object,
and must be in the format of name=value
.
- Java
-
以下示例显示了作为作业参数传递给在 Java 中定义的作业的日期:
The following example shows a date passed as a job parameter to a job defined in Java:
<bash$ java CommandLineJobRunner io.spring.EndOfDayJobConfiguration endOfDay schedule.date=2007-05-05,java.time.LocalDate
- XML
-
以下范例显示一个日期传递为作业参数到 XML 中定义的作业:
The following example shows a date passed as a job parameter to a job defined in XML:
<bash$ java CommandLineJobRunner endOfDayJob.xml endOfDay schedule.date=2007-05-05,java.time.LocalDate
默认情况下, By default, the 在以下范例中, In the following example,
你可以使用自定义 You can override this behavior by using a custom |
- Java
-
在大多数情况下,你都希望使用清单在 jar 中声明
main
类。但是,为简单起见,直接使用了该类。此示例从 The Domain Language of Batch 中使用了EndOfDay
示例。第一个参数是io.spring.EndOfDayJobConfiguration
,它是包含 Job 的配置类中完全限定的类名称。第二个参数endOfDay
表示 job 名称。最终参数schedule.date=2007-05-05,java.time.LocalDate
转换为类型java.time.LocalDate
的JobParameter
对象。
In most cases, you would want to use a manifest to declare your main
class in a jar. However,
for simplicity, the class was used directly. This example uses the EndOfDay
example from the The Domain Language of Batch. The first
argument is io.spring.EndOfDayJobConfiguration
, which is the fully qualified class name
to the configuration class that contains the Job. The second argument, endOfDay
, represents
the job name. The final argument, schedule.date=2007-05-05,java.time.LocalDate
, is converted
into a JobParameter
object of type java.time.LocalDate
.
以下范例显示一个 EndOfDay
配置范例在 Java 中:
The following example shows a sample configuration for endOfDay
in Java:
@Configuration
@EnableBatchProcessing
public class EndOfDayJobConfiguration {
@Bean
public Job endOfDay(JobRepository jobRepository, Step step1) {
return new JobBuilder("endOfDay", jobRepository)
.start(step1)
.build();
}
@Bean
public Step step1(JobRepository jobRepository, PlatformTransactionManager transactionManager) {
return new StepBuilder("step1", jobRepository)
.tasklet((contribution, chunkContext) -> null, transactionManager)
.build();
}
}
- XML
-
在大多数情况下,你都希望使用清单在 jar 中声明
main
类。但是,由于简单起见,直接使用了该类。此示例从 The Domain Language of Batch 中使用了EndOfDay
示例。第一个参数是endOfDayJob.xml
,它是包含Job
的 Spring ApplicationContext。第二个参数endOfDay,
表示 job 名称。最终参数schedule.date=2007-05-05,java.time.LocalDate
转换为类型为java.time.LocalDate
的JobParameter
对象。
In most cases, you would want to use a manifest to declare your main
class in a jar. However,
for simplicity, the class was used directly. This example uses the EndOfDay
example from the The Domain Language of Batch. The first
argument is endOfDayJob.xml
, which is the Spring ApplicationContext that contains the
Job
. The second argument, endOfDay,
represents the job name. The final argument,
schedule.date=2007-05-05,java.time.LocalDate
, is converted into a JobParameter
object of type
java.time.LocalDate
.
以下范例显示一个 EndOfDay
配置范例在 XML 中:
The following example shows a sample configuration for endOfDay
in XML:
<job id="endOfDay">
<step id="step1" parent="simpleStep" />
</job>
<!-- Launcher details removed for clarity -->
<beans:bean id="jobLauncher"
class="org.springframework.batch.core.launch.support.TaskExecutorJobLauncher" />
前面的范例过于简单,因为一般在 Spring Batch 中运行批处理作业有许多更多需求,但它有助于展示 CommandLineJobRunner
的两个主要需求:Job
和 JobLauncher
。
The preceding example is overly simplistic, since there are many more requirements to a
run a batch job in Spring Batch in general, but it serves to show the two main
requirements of the CommandLineJobRunner
: Job
and JobLauncher
.
Exit Codes
从命令行启动批处理作业的时候,通常会使用企业调度程序。大多数调度程序相当愚蠢,并且仅在进程级别工作。这意味着它们只了解某些操作系统进程(如它们调用的 shell 脚本)。在此场景中,向调度程序返回作业成功或失败的唯一方法是通过返回码。返回码是进程返回给调度程序的一个数字,表示运行结果。在最简单的情况下,0 代表成功,1 代表失败。然而,可能存在更复杂的情况,例如:“如果作业 A 返回 4,则启动作业 B;如果返回 5,则启动作业 C。”此类行为在调度程序级别配置,但重要的是一个像 Spring Batch 这样的处理框架提供一种方法,返回给定批处理作业的退出码的数字表示形式。在 Spring Batch 中,这被封装到一个 ExitStatus
中,在第 5 章中会更详细地讨论。就讨论退出码而言,唯一重要的要知道的事情是:ExitStatus
拥有一个框架(或开发人员)设置的退出码属性,并且作为 JobLauncher
返回的 JobExecution
的一部分返回。CommandLineJobRunner
使用 ExitCodeMapper
接口将此字符串值转换为一个数字:
When launching a batch job from the command-line, an enterprise
scheduler is often used. Most schedulers are fairly dumb and work only
at the process level. This means that they only know about some
operating system process (such as a shell script that they invoke).
In this scenario, the only way to communicate back to the scheduler
about the success or failure of a job is through return codes. A
return code is a number that is returned to a scheduler by the process
to indicate the result of the run. In the simplest case, 0 is
success and 1 is failure. However, there may be more complex
scenarios, such as “If job A returns 4, kick off job B, and, if it returns 5, kick
off job C.” This type of behavior is configured at the scheduler level,
but it is important that a processing framework such as Spring Batch
provide a way to return a numeric representation of the exit code
for a particular batch job. In Spring Batch, this is encapsulated
within an ExitStatus
, which is covered in more
detail in Chapter 5. For the purposes of discussing exit codes, the
only important thing to know is that an
ExitStatus
has an exit code property that is
set by the framework (or the developer) and is returned as part of the
JobExecution
returned from the
JobLauncher
. The
CommandLineJobRunner
converts this string value
to a number by using the ExitCodeMapper
interface:
public interface ExitCodeMapper {
public int intValue(String exitCode);
}
ExitCodeMapper
的重要契约是,给定一个字符串退出码,将返回一个数字表示形式。作业运行器使用的默认实现是 SimpleJvmExitCodeMapper
,如果完成则返回 0,如果有通用错误则返回 1,如果有任何作业运行器错误(如在所提供的上下文中找不到 Job
)则返回 2。如果需要比上面三个值更复杂的东西,则必须提供 ExitCodeMapper
接口的自定义实现。因为 CommandLineJobRunner
是创建 ApplicationContext
的类,因此无法“接线”,任何需要覆盖的值都必须自动连接。这意味着如果在 BeanFactory
中找到 ExitCodeMapper
实现,则会在创建该上下文后将其注入到运行器中。所需要做的就是提供你自己的 ExitCodeMapper
,声明该实现作为一个根级别 Bean,并确保它是运行器加载的 ApplicationContext
的一部分。
The essential contract of an
ExitCodeMapper
is that, given a string exit
code, a number representation will be returned. The default
implementation used by the job runner is the SimpleJvmExitCodeMapper
that returns 0 for completion, 1 for generic errors, and 2 for any job
runner errors such as not being able to find a
Job
in the provided context. If anything more
complex than the three values above is needed, a custom
implementation of the ExitCodeMapper
interface
must be supplied. Because the
CommandLineJobRunner
is the class that creates
an ApplicationContext
and, thus, cannot be
'wired together', any values that need to be overwritten must be
autowired. This means that if an implementation of
ExitCodeMapper
is found within the BeanFactory
,
it is injected into the runner after the context is created. All
that needs to be done to provide your own
ExitCodeMapper
is to declare the implementation
as a root level bean and ensure that it is part of the
ApplicationContext
that is loaded by the
runner.
Running Jobs from within a Web Container
从历史上看,离线处理(例如批处理作业)已经从命令行启动,如前所述。然而,在许多情况下,从 HttpRequest
启动是一个更好的选择。许多这样的用例包括报告、即席作业运行和 Web 应用程序支持。因为批处理作业(根据定义)是长时间运行的,所以最重要的考虑是异步地启动作业:
Historically, offline processing (such as batch jobs) has been
launched from the command-line, as described earlier. However, there are
many cases where launching from an HttpRequest
is
a better option. Many such use cases include reporting, ad-hoc job
running, and web application support. Because a batch job (by definition)
is long running, the most important concern is to launch the
job asynchronously:

在这种情况下,控制器是 Spring MVC 控制器。有关 Spring MVC 的更多信息,请参阅 Spring 框架参考指南。该控制器使用已配置为启动 asynchronously 的 JobLauncher
启动 Job
,从而立即返回 JobExecution
。Job
仍可能在运行。但是,此非阻塞行为使控制器可以立即返回,这是处理 HttpRequest
时必需的。以下清单显示了一个示例:
The controller in this case is a Spring MVC controller. See the
Spring Framework Reference Guide for more about Spring MVC.
The controller launches a Job
by using a
JobLauncher
that has been configured to launch
asynchronously, which
immediately returns a JobExecution
. The
Job
is likely still running. However, this
nonblocking behavior lets the controller return immediately, which
is required when handling an HttpRequest
. The following listing
shows an example:
@Controller
public class JobLauncherController {
@Autowired
JobLauncher jobLauncher;
@Autowired
Job job;
@RequestMapping("/jobLauncher.html")
public void handle() throws Exception{
jobLauncher.run(job, new JobParameters());
}
}