运行作业
启动一个批处理作业至少需要两样东西:要启动的 Job 和一个 JobOperator。这两者可以包含在同一个上下文中,也可以在不同的上下文中。例如,如果你从命令行启动作业,每个 Job 都会实例化一个新的 JVM。因此,每个作业都有自己的 JobOperator。然而,如果你在 HttpRequest 范围内的 Web 容器中运行,通常会有一个 JobOperator(配置为异步作业启动),多个请求会调用它来启动它们的作业。
从命令行运行作业
若您希望从企业级调度器运行作业,命令行将是主要交互界面。这是因为大多数调度器(除Quartz外,除非使用 NativeJob)直接与操作系统进程交互,通常通过shell脚本启动。除了shell脚本外,启动Java进程还有许多其他方式,例如使用Perl、Ruby,甚至构建工具如Ant或Maven。然而,由于大多数人对shell脚本较为熟悉,本例将重点介绍此方法。
CommandLineJobOperator
由于启动作业的脚本需要启动一个 Java 虚拟机,因此必须有一个包含 main 方法的类作为主要入口点。Spring Batch 提供了一个实现此目的的类:CommandLineJobOperator。请注意,这只是引导应用程序的一种方式。启动 Java 进程的方法有很多种,不应将此类视为唯一标准。CommandLineJobOperator 执行以下四个任务:
- 加载相应的
ApplicationContext。 - 将命令行参数解析为
JobParameters。 - 根据参数定位相应的作业。
- 使用应用程序上下文中提供的
JobOperator来启动作业。
所有这些任务都仅通过传入的参数完成。下表描述了所需的参数:
表 1. CommandLineJobOperator 参数
jobClass | 用于创建 ApplicationContext 的作业配置类的完全限定名。该文件应包含运行完整 Job 所需的一切,包括 JobOperator、JobRepository 以及填充了待操作作业的 JobRegistry。 |
|---|---|
operation | 要在作业上执行的操作名称。可以是以下之一:[start, startNextInstance, stop, restart, abandon] |
jobName 或 jobExecutionId | 根据操作的不同,这可以是待启动作业的名称,或者是待停止、重启、放弃或恢复的作业的执行 ID。 |
启动任务时,这些参数之后的所有参数均被视为任务参数,它们会被转换为 JobParameters 对象,且必须遵循 name=value,type,identifying 的格式。而在停止、重启、放弃或恢复任务时,第四个参数应为 jobExecutionId,其余所有参数将被忽略。
以下示例展示了将日期作为作业参数传递给在 Java 中定义的作业:
<bash$ java CommandLineJobOperator io.spring.EndOfDayJobConfiguration start endOfDay schedule.date=2007-05-05,java.time.LocalDate
默认情况下,CommandLineJobOperator 使用 DefaultJobParametersConverter,该转换器会将键/值对隐式转换为标识性作业参数。不过,您也可以通过为参数分别添加 true 或 false 后缀,来明确指定哪些作业参数是标识性的,哪些不是。
在以下示例中,schedule.date 是一个标识性作业参数,而 vendor.id 则不是:
<bash$ java CommandLineJobOperator io.spring.EndOfDayJobConfiguration start endOfDay \
schedule.date=2007-05-05,java.time.LocalDate,true \
vendor.id=123,java.lang.Long,false
你可以通过在 CommandLineJobOperator 上设置自定义的 JobParametersConverter 来覆盖此行为。
退出代码
当从命令行启动批处理作业时,通常会使用企业级调度器。大多数调度器功能较为简单,仅能在进程级别工作。这意味着它们仅了解某些操作系统进程(例如它们调用的shell脚本)。在此场景下,向调度器反馈作业成功或失败的唯一方式是通过返回码。返回码是进程返回给调度器以指示运行结果的数字。在最简单的情况下,0表示成功,1表示失败。但可能存在更复杂的场景,例如"如果作业A返回4,则启动作业B;如果返回5,则启动作业C"。这类行为在调度器层面进行配置,但像Spring Batch这样的处理框架必须提供返回特定批处理作业退出码数字表示的方法,这一点至关重要。在Spring Batch中,该机制封装于ExitStatus中(第5章将详细说明)。就讨论退出码而言,唯一需要了解的是:ExitStatus具有由框架(或开发者)设置的退出码属性,该属性作为JobOperator返回的JobExecution的一部分进行返回。CommandLineJobOperator通过ExitCodeMapper接口将此字符串值转换为数字:
public interface ExitCodeMapper {
int intValue(String exitCode);
}
ExitCodeMapper 的核心契约是:给定一个字符串形式的退出码,它将返回对应的数字表示。作业运行器默认使用的实现是 SimpleJvmExitCodeMapper,该实现会在作业完成时返回 0,发生通用错误时返回 1,而遇到任何作业运行器错误(例如在提供的上下文中找不到 Job)时则返回 2。如果需要处理比上述三种情况更复杂的退出码映射,则必须通过自定义实现 ExitCodeMapper 接口,并将其设置在 CommandLineJobOperator 上来提供。
从 Web 容器内运行作业
历史上,离线处理(如批处理作业)通常是从命令行启动的,如前所述。然而,在许多情况下,从 HttpRequest 启动是更好的选择。这类用例包括报告、临时作业运行和 Web 应用程序支持。由于批处理作业(根据定义)是长时间运行的,最重要的考虑是异步启动作业:

图 1. 从 Web 容器启动异步作业的时序图
在本例中,控制器是一个 Spring MVC 控制器。有关 Spring MVC 的更多信息,请参阅 Spring Framework 参考指南。该控制器通过使用已配置为异步启动的 JobOperator 来启动一个 Job,并立即返回一个 JobExecution。此时 Job 很可能仍在运行。然而,这种非阻塞行为使得控制器能够立即返回,这在处理 HttpRequest 时是必需的。以下示例展示了具体实现:
@Controller
public class JobOperatorController {
@Autowired
JobOperator jobOperator;
@Autowired
Job job;
@RequestMapping("/jobOperator.html")
public void handle() throws Exception{
jobOperator.start(job, new JobParameters());
}
}