|
对于最新稳定版本,请使用 Spring Batch 文档 6.0.3! |
运行任务
至少,启动一个批处理作业需要两件事:要启动的Job和一个JobLauncher。两者可以包含在同一个上下文中,也可以包含在不同的上下文中。例如,如果您从命令行启动作业,则每个Job都会实例化一个新的 JVM。因此,每个作业都有自己独立的JobLauncher。然而,如果您在位于HttpRequest作用域内的 Web 容器中运行,则通常只有一个JobLauncher(配置用于异步启动作业),多个请求会调用它来启动各自的作业。
从命令行运行作业
如果您想从企业级调度器运行作业,命令行是主要接口。这是因为大多数调度器(除了 Quartz,除非使用 NativeJob)直接操作系统进程,通常通过 shell 脚本启动。除了 shell 脚本外,还有许多方式可以启动 Java 进程,例如使用 Perl、Ruby,甚至构建工具如 Ant 或 Maven。然而,由于大多数人熟悉 shell 脚本,本示例将重点介绍它们。
CommandLineJobRunner
由于启动作业的脚本必须启动一个 Java 虚拟机,因此需要一个包含 main 方法的类作为主要入口点。Spring Batch 提供了一个实现来满足此目的:CommandLineJobRunner。请注意,这只是引导应用程序的一种方式。启动 Java 进程的方法有很多,绝不应将此类视为唯一标准。CommandLineJobRunner 执行以下四项任务:
-
加载适当的
ApplicationContext。 -
将命令行参数解析为
JobParameters。 -
根据参数定位合适的工作。
-
使用应用上下文中提供的
JobLauncher来启动作业。
所有这些任务仅通过传入的参数即可完成。 下表描述了所需的参数:
|
用于创建 |
|
要运行的作业名称。 |
这些参数必须传入,首先是路径,其次是名称。在此之后的所有参数都被视为作业参数,会被转换为 JobParameters 对象,并且必须符合 name=value 格式。
-
Java
-
XML
以下示例展示了将日期作为作业参数传递给在 Java 中定义的作业:
<bash$ java CommandLineJobRunner io.spring.EndOfDayJobConfiguration endOfDay schedule.date=2007-05-05,java.time.LocalDate
以下示例展示了将日期作为作业参数传递给在 XML 中定义的作业:
<bash$ java CommandLineJobRunner endOfDayJob.xml endOfDay schedule.date=2007-05-05,java.time.LocalDate
|
默认情况下, 在以下示例中,
您可以通过使用自定义的 |
-
Java
-
XML
在大多数情况下,您会希望使用清单文件在 jar 中声明您的 main 类。然而,为了简化,此处直接使用了该类。本示例采用了来自 批处理的领域语言 的 EndOfDay 示例。第一个参数是 io.spring.EndOfDayJobConfiguration,即包含作业(Job)的配置类的完全限定类名。第二个参数 endOfDay 代表作业名称。最后一个参数 schedule.date=2007-05-05,java.time.LocalDate 将被转换为类型为 java.time.LocalDate 的 JobParameter 对象。
以下示例展示了在 Java 中为 endOfDay 配置的样例:
@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();
}
}
在大多数情况下,您会希望使用清单文件在 jar 包中声明您的 main 类。然而,为了简化,此处直接使用了该类。本示例采用了来自 批处理的领域语言 的 EndOfDay 示例。第一个参数是 endOfDayJob.xml,即包含 Job 的 Spring ApplicationContext。第二个参数 endOfDay, 代表作业名称。最后一个参数 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。
退出代码
从命令行启动批处理作业时,通常会使用企业级调度器。大多数调度器相当笨拙,仅在进程级别工作。这意味着它们只知道某些操作系统进程(例如它们调用的 shell 脚本)。在此场景中,向调度器传达作业成功或失败的唯一方式是通过返回码。A
返回码是一个由进程返回给调度器的数字,
用于指示运行结果。在最简单的情况下,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的一部分。
在 Web 容器内运行作业
历史上,离线处理(例如批处理作业)如前所述是从命令行启动的。然而,在许多情况下,从 HttpRequest 启动是更好的选择。许多此类用例包括报表生成、临时作业运行以及 Web 应用程序支持。由于批处理作业(根据其定义)运行时间较长,因此最重要的关注点是异步启动该作业:
此情况下的控制器是一个 Spring MVC 控制器。有关 Spring MVC 的更多信息,请参阅 Spring Framework 参考指南。
该控制器通过使用已配置为 异步 启动的 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());
}
}