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
来启动它们的作业。
Running Jobs from the Command Line
如果你想从企业计划程序运行作业,则命令行是主要接口。这是因为大多数计划程序(Quartz 除外,除非使用 NativeJob
)直接与操作系统进程一起工作,主要是用 shell 脚本启动的。除了 shell 脚本之外,还有许多方法可以启动 Java 进程,例如 Perl、Ruby,甚至构建工具,例如 Ant 或 Maven。然而,由于大多数人熟悉 shell 脚本,所以本示例重点关注它们。
The CommandLineJobRunner
由于启动作业的脚本必须启动 Java Virtual Machine,因此需要有一个带有 main
方法的类充当主要入口点。Spring Batch 提供了一个实现来实现此目的:CommandLineJobRunner
。请注意,这只是引导应用程序的一种方式。有许多方法可以启动 Java 进程,此类决不应被视为明确的。CommandLineJobRunner
执行四项任务:
-
Load the appropriate
ApplicationContext
. -
将命令行参数解析为
JobParameters
。 -
根据参数找到适当的工作。
-
使用应用程序上下文中提供的
JobLauncher
来启动作业。
所有这些任务仅使用传入的参数完成。下表描述了必需的参数:
|
用于创建 |
|
要运行作业的名称。 |
必须传入这些参数,先输入路径,然后再输入名称。这些之后的所有参数都被视为作业参数,变为一个 JobParameters
对象,并且必须采用 name=value
格式。
- Java
-
以下示例显示了作为作业参数传递给在 Java 中定义的作业的日期:
<bash$ java CommandLineJobRunner io.spring.EndOfDayJobConfiguration endOfDay schedule.date=2007-05-05,java.time.LocalDate
- XML
-
以下范例显示一个日期传递为作业参数到 XML 中定义的作业:
<bash$ java CommandLineJobRunner endOfDayJob.xml endOfDay schedule.date=2007-05-05,java.time.LocalDate
默认情况下,
你可以使用自定义 |
- 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
对象。 以下范例显示一个EndOfDay
配置范例在 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
对象。 以下范例显示一个EndOfDay
配置范例在 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
。
Exit Codes
从命令行启动批处理作业的时候,通常会使用企业调度程序。大多数调度程序相当愚蠢,并且仅在进程级别工作。这意味着它们只了解某些操作系统进程(如它们调用的 shell 脚本)。在此场景中,向调度程序返回作业成功或失败的唯一方法是通过返回码。返回码是进程返回给调度程序的一个数字,表示运行结果。在最简单的情况下,0 代表成功,1 代表失败。然而,可能存在更复杂的情况,例如:“如果作业 A 返回 4,则启动作业 B;如果返回 5,则启动作业 C。”此类行为在调度程序级别配置,但重要的是一个像 Spring Batch 这样的处理框架提供一种方法,返回给定批处理作业的退出码的数字表示形式。在 Spring Batch 中,这被封装到一个 ExitStatus
中,在第 5 章中会更详细地讨论。就讨论退出码而言,唯一重要的要知道的事情是:ExitStatus
拥有一个框架(或开发人员)设置的退出码属性,并且作为 JobLauncher
返回的 JobExecution
的一部分返回。CommandLineJobRunner
使用 ExitCodeMapper
接口将此字符串值转换为一个数字:
public interface ExitCodeMapper {
public int intValue(String exitCode);
}
ExitCodeMapper
的重要契约是,给定一个字符串退出码,将返回一个数字表示形式。作业运行器使用的默认实现是 SimpleJvmExitCodeMapper
,如果完成则返回 0,如果有通用错误则返回 1,如果有任何作业运行器错误(如在所提供的上下文中找不到 Job
)则返回 2。如果需要比上面三个值更复杂的东西,则必须提供 ExitCodeMapper
接口的自定义实现。因为 CommandLineJobRunner
是创建 ApplicationContext
的类,因此无法“接线”,任何需要覆盖的值都必须自动连接。这意味着如果在 BeanFactory
中找到 ExitCodeMapper
实现,则会在创建该上下文后将其注入到运行器中。所需要做的就是提供你自己的 ExitCodeMapper
,声明该实现作为一个根级别 Bean,并确保它是运行器加载的 ApplicationContext
的一部分。
Running Jobs from within a Web Container
从历史上看,离线处理(例如批处理作业)已经从命令行启动,如前所述。然而,在许多情况下,从 HttpRequest
启动是一个更好的选择。许多这样的用例包括报告、即席作业运行和 Web 应用程序支持。因为批处理作业(根据定义)是长时间运行的,所以最重要的考虑是异步地启动作业:
在这种情况下,控制器是 Spring MVC 控制器。有关 Spring MVC 的更多信息,请参阅 Spring 框架参考指南。该控制器使用已配置为启动 asynchronously 的 JobLauncher
启动 Job
,从而立即返回 JobExecution
。Job
仍可能在运行。但是,此非阻塞行为使控制器可以立即返回,这是处理 HttpRequest
时必需的。以下清单显示了一个示例:
@Controller
public class JobLauncherController {
@Autowired
JobLauncher jobLauncher;
@Autowired
Job job;
@RequestMapping("/jobLauncher.html")
public void handle() throws Exception{
jobLauncher.run(job, new JobParameters());
}
}