配置和运行作业
配置和运行作业
在 domain 部分 ,总体 讨论了架构设计,使用下图作为 指导:
虽然该对象可能看起来很简单
容器中,有许多配置选项,其中
开发人员必须知道。此外,还有许多考虑因素
a 将如何运行以及其元数据将如何
在该运行期间存储。本章将解释各种配置
选项和运行时问题。Job
Job
Job
配置 Job
Job
接口有多种实现。然而
构建器抽象出配置中的差异。
@Bean
public Job footballJob() {
return this.jobBuilderFactory.get("footballJob")
.start(playerLoad())
.next(gameLoad())
.next(playerSummarization())
.build();
}
A(通常包含其中的任何 A 值)需要 .这
的配置是通过 BatchConfigurer
处理的。Job
Step
JobRepository
JobRepository
上面的示例说明了由三个实例组成的 a。工作相关
构建器还可以包含其他有助于并行化的元素 (),
声明式流控制 () 和流定义外部化 ()。Job
Step
Split
Decision
Flow
无论您使用 Java 还是 XML,Job
接口都有多种实现。但是,命名空间抽象出了配置中的差异。它有
只有三个必需的依赖项:名称、 和实例列表。JobRepository
Step
<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' 的存储库,该 是合理的默认值。但是,这可以显式覆盖:
<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/>
可重启性
执行批处理作业时的一个关键问题涉及
重新 启动。如果特定 已存在 a,则 a 的启动被视为“重新启动”。理想情况下,所有作业都应该能够启动
从他们离开的地方开始,但在某些情况下这是不可能的。是的
完全由开发人员来确保在此
场景。但是,Spring Batch 确实提供了一些帮助。如果 a 不应该是
重新启动,但应始终作为 new 的一部分运行,则
restartable 属性可以设置为 'false'。
Job
Job
JobExecution
JobInstance
Job
JobInstance
以下示例演示如何在 XML 中将字段设置为 :restartable
false
<job id="footballJob" restartable="false">
...
</job>
以下示例演示如何在 Java 中将字段设置为 :restartable
false
@Bean
public Job footballJob() {
return this.jobBuilderFactory.get("footballJob")
.preventRestart()
...
.build();
}
换句话说,将 restartable 设置为 false 意味着 “this does not support being started again”。重新启动 不是
restartable 会导致
被扔掉。Job
Job
JobRestartException
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
}
此 JUnit 代码片段显示了如何尝试首次为不可重启的
job 不会造成任何问题。然而,第二个
尝试将抛出 .JobExecution
JobRestartException
拦截任务执行
在执行
工作,通知各种可能很有用
事件,以便可以执行自定义代码。这允许在适当的时间调用 a 来实现这一点:SimpleJob
JobListener
public interface JobExecutionListener {
void beforeJob(JobExecution jobExecution);
void afterJob(JobExecution jobExecution);
}
JobListeners
可以通过在 Job 上设置 listeners 添加到 中。SimpleJob
以下示例演示如何将侦听器元素添加到 XML 作业定义中:
<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>
以下示例说明如何将侦听器方法添加到 Java 作业定义中:
@Bean
public Job footballJob() {
return this.jobBuilderFactory.get("footballJob")
.listener(sampleListener())
...
.build();
}
需要注意的是,无论成功还是
失败的 .如果需要确定成功或失败,可以获取
从 ,如下所示:afterJob
Job
JobExecution
public void afterJob(JobExecution jobExecution){
if (jobExecution.getStatus() == BatchStatus.COMPLETED ) {
//job success
}
else if (jobExecution.getStatus() == BatchStatus.FAILED) {
//job failure
}
}
与此接口对应的注解是:
-
@BeforeJob
-
@AfterJob
从父作业继承
如果一组 Job 具有相似但不是
相同的配置,则定义一个 “父项” 可能会有所帮助,具体
Job 可以继承 properties。与 class 相似
继承,则 “child” 将合并
它的元素和属性与父级的 Elements 和 Attributes 一起使用。Job
Job
在下面的示例中,“baseJob” 是一个抽象定义,它只定义了
听众。“job1” 是一个具体的
从 “baseJob” 继承侦听器列表并合并的定义
it 替换为自己的侦听器列表,以生成一个包含两个侦听器和一个 “step1” 的 a。Job
Job
Job
Step
<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>
有关更多详细信息,请参阅从父步骤继承部分。
JobParametersValidator (作业参数验证器)
在 XML 命名空间中声明的作业或使用 的任何子类可以选择为
运行。例如,当您需要断言作业
启动其所有必需参数。有一个 可以用来约束组合
简单的强制和可选参数,以及更复杂的
constraints 中,您可以自行实现接口。AbstractJob
DefaultJobParametersValidator
验证器的配置是通过 XML 命名空间通过子 元素,如以下示例所示:
<job id="job1" parent="baseJob3">
<step id="step1" parent="standaloneStep"/>
<validator ref="parametersValidator"/>
</job>
验证器可以指定为引用(如前所述)或嵌套 bean 定义。
验证器的配置通过 java 构建器支持,如 以下示例:
@Bean
public Job job1() {
return this.jobBuilderFactory.get("job1")
.validator(parametersValidator())
...
.build();
}
Java 配置
Spring 3 带来了通过 Java 而不是 XML 配置应用程序的能力。截至
Spring Batch 2.2.0 中,可以使用相同的 java 配置来配置批处理作业。
基于 java 的配置有两个组件:annotation 和两个构建器。@EnableBatchProcessing
其工作@Enable方式类似于
Spring 家族。在这种情况下,为
构建批处理作业。在此基本配置中,is 的实例
除了许多可用于自动装配的 bean 之外,还创建了:@EnableBatchProcessing
@EnableBatchProcessing
StepScope
-
JobRepository
:Bean 名称 “jobRepository” -
JobLauncher
: bean 名称 “jobLauncher” -
JobRegistry
: Bean 名称 “jobRegistry” -
PlatformTransactionManager
: Bean 名称 “transactionManager” -
JobBuilderFactory
:bean 名称 “jobBuilders” -
StepBuilderFactory
:Bean 名称 “stepBuilders”
此配置的核心接口是 .默认的
implementation 提供上面提到的 bean,并且需要一个 AS bean
在要提供的上下文中。此数据源由 JobRepository 使用。
您可以自定义这些 bean 中的任何一个
通过创建 Interface 的自定义实现。
通常,扩展 the (如果未找到 a ,则提供)并覆盖所需的 getter 就足够了。
但是,可能需要从头开始实现自己的 API。以下内容
示例展示了如何提供自定义事务管理器:BatchConfigurer
DataSource
BatchConfigurer
DefaultBatchConfigurer
BatchConfigurer
@Bean
public BatchConfigurer batchConfigurer(DataSource dataSource) {
return new DefaultBatchConfigurer(dataSource) {
@Override
public PlatformTransactionManager getTransactionManager() {
return new MyTransactionManager();
}
};
}
只有一个 configuration class 需要有 annotation。一次
你有一个用它注释的类,你将拥有以上所有内容。 |
有了基本配置,用户就可以使用提供的构建器工厂来
配置作业。以下示例显示了一个配置了 和 的两步作业:JobBuilderFactory
StepBuilderFactory
@Configuration
@EnableBatchProcessing
@Import(DataSourceConfiguration.class)
public class AppConfig {
@Autowired
private JobBuilderFactory jobs;
@Autowired
private StepBuilderFactory steps;
@Bean
public Job job(@Qualifier("step1") Step step1, @Qualifier("step2") Step step2) {
return jobs.get("myJob").start(step1).next(step2).build();
}
@Bean
protected Step step1(ItemReader<Person> reader,
ItemProcessor<Person, Person> processor,
ItemWriter<Person> writer) {
return steps.get("step1")
.<Person, Person> chunk(10)
.reader(reader)
.processor(processor)
.writer(writer)
.build();
}
@Bean
protected Step step2(Tasklet tasklet) {
return steps.get("step2")
.tasklet(tasklet)
.build();
}
}
配置 JobRepository
使用 时,将为您提供开箱即用的 a。
本节介绍如何配置您自己的。@EnableBatchProcessing
JobRepository
如前所述,JobRepository
用于各种持久化
Spring Batch 中的域对象,例如 和 。许多主要都需要它
框架功能,例如 、 和 .JobExecution
StepExecution
JobLauncher
Job
Step
batch 命名空间抽象出 implementations 及其协作者的许多实现细节。但是,仍然有一些
可用的配置选项,如以下示例所示:JobRepository
<job-repository id="jobRepository"
data-source="dataSource"
transaction-manager="transactionManager"
isolation-level-for-create="SERIALIZABLE"
table-prefix="BATCH_"
max-varchar-length="1000"/>
上面列出的配置选项都不是必需的,除了 .如果他们是
未设置,则将使用上面显示的默认值。它们显示在上面是为了提高知名度
目的。默认值为 2500,这是示例架构中长列的长度
脚本。id
max-varchar-length
VARCHAR
使用 java 配置时,将为您提供 a。基于 JDBC 的 API 是
如果提供了 a,则提供开箱即用,如果没有,则提供基于 one。然而
您可以通过 interface 的实现自定义 的配置。JobRepository
DataSource
Map
JobRepository
BatchConfigurer
...
// This would reside in your BatchConfigurer implementation
@Override
protected JobRepository createJobRepository() throws Exception {
JobRepositoryFactoryBean factory = new JobRepositoryFactoryBean();
factory.setDataSource(dataSource);
factory.setTransactionManager(transactionManager);
factory.setIsolationLevelForCreate("ISOLATION_SERIALIZABLE");
factory.setTablePrefix("BATCH_");
factory.setMaxVarCharLength(1000);
return factory.getObject();
}
...
上面列出的任何配置选项都不是必需的,但
dataSource 和 transactionManager.如果未设置,则使用上面显示的默认值
将被使用。它们在上面显示是为了提高认识目的。这
Max Varchar Length 默认为 2500,即
示例架构脚本中长列的长度VARCHAR
JobRepository 的事务配置
如果使用 namespace 或 provided ,则事务性建议为
围绕存储库自动创建。这是为了确保批量元数据
包括失败后重新启动所需的状态将正确保留。
如果存储库方法不是
事务。指定 method 属性中的隔离级别
以确保在启动作业时,如果两个进程尝试启动
同一时间执行相同的作业,只有一个成功。该
方法是 ,这是相当激进的。 将
井。 如果两个进程不太可能在此发生冲突,那就很好了
道路。但是,由于对该方法的调用非常短,因此只要数据库平台支持它,就不太可能导致问题。但是,此
可以覆盖。FactoryBean
create*
SERIALIZABLE
READ_COMMITTED
READ_UNCOMMITTED
create*
SERIALIZED
以下示例演示如何在 XML 中覆盖隔离级别:
<job-repository id="jobRepository"
isolation-level-for-create="REPEATABLE_READ" />
以下示例演示如何在 Java 中覆盖隔离级别:
// This would reside in your BatchConfigurer implementation
@Override
protected JobRepository createJobRepository() throws Exception {
JobRepositoryFactoryBean factory = new JobRepositoryFactoryBean();
factory.setDataSource(dataSource);
factory.setTransactionManager(transactionManager);
factory.setIsolationLevelForCreate("ISOLATION_REPEATABLE_READ");
return factory.getObject();
}
如果未使用名称空间或工厂 bean,则还必须配置 使用 AOP 的存储库的事务行为。
以下示例显示如何配置存储库的事务行为 在 XML 中:
<aop:config>
<aop:advisor
pointcut="execution(* org.springframework.batch.core..*Repository+.*(..))"/>
<advice-ref="txAdvice" />
</aop:config>
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<tx:attributes>
<tx:method name="*" />
</tx:attributes>
</tx:advice>
前面的片段几乎可以按原样使用,几乎没有任何更改。还要记住 包括适当的名称空间声明,并确保 spring-tx 和 spring-aop (或整个 Spring)都在 Classpath 上。
以下示例显示如何配置存储库的事务行为 在 Java 中:
@Bean
public TransactionProxyFactoryBean baseProxy() {
TransactionProxyFactoryBean transactionProxyFactoryBean = new TransactionProxyFactoryBean();
Properties transactionAttributes = new Properties();
transactionAttributes.setProperty("*", "PROPAGATION_REQUIRED");
transactionProxyFactoryBean.setTransactionAttributes(transactionAttributes);
transactionProxyFactoryBean.setTarget(jobRepository());
transactionProxyFactoryBean.setTransactionManager(transactionManager());
return transactionProxyFactoryBean;
}
更改表前缀
的另一个可修改属性是元数据的表前缀
表。默认情况下,它们都以 . 和 是两个例子。但是,有一些潜在的原因需要修改它
前缀。如果需要将架构名称添加到表名称前面,或者如果有多个
的 meta data tables 集,则表前缀需要
被更改:JobRepository
BATCH_
BATCH_JOB_EXECUTION
BATCH_STEP_EXECUTION
以下示例演示如何更改 XML 中的表前缀:
<job-repository id="jobRepository"
table-prefix="SYSTEM.TEST_" />
以下示例演示如何在 Java 中更改表前缀:
// This would reside in your BatchConfigurer implementation
@Override
protected JobRepository createJobRepository() throws Exception {
JobRepositoryFactoryBean factory = new JobRepositoryFactoryBean();
factory.setDataSource(dataSource);
factory.setTransactionManager(transactionManager);
factory.setTablePrefix("SYSTEM.TEST_");
return factory.getObject();
}
鉴于上述更改,对元数据表的每个查询都以 为前缀。 称为 SYSTEM..SYSTEM.TEST_
BATCH_JOB_EXECUTION
TEST_JOB_EXECUTION
只有表前缀是可配置的。table 和 column name 不是。 |
内存存储库
在某些情况下,您可能不希望将域对象持久化到
数据库。一个原因可能是速度;在每个提交点存储域对象需要额外的
时间。另一个原因可能是您不需要为特定
工作。因此, Spring Batch 提供了作业的内存中版本
存储 库。Map
以下示例显示了 XML 中包含的内容:MapJobRepositoryFactoryBean
<bean id="jobRepository"
class="org.springframework.batch.core.repository.support.MapJobRepositoryFactoryBean">
<property name="transactionManager" ref="transactionManager"/>
</bean>
以下示例显示了 Java 中包含的:MapJobRepositoryFactoryBean
// This would reside in your BatchConfigurer implementation
@Override
protected JobRepository createJobRepository() throws Exception {
MapJobRepositoryFactoryBean factory = new MapJobRepositoryFactoryBean();
factory.setTransactionManager(transactionManager);
return factory.getObject();
}
请注意,内存存储库是可变的,因此不允许在 JVM 之间重新启动
实例。它也不能保证具有相同参数的两个作业实例是
同时启动,不适合在多线程 Job 中使用,也不适合在本地
分区。因此,在您需要的地方使用存储库的数据库版本
特征。Step
但是,它确实需要定义事务管理器,因为存在回滚
语义,并且因为业务逻辑可能仍是
事务性(如 RDBMS 访问)。出于测试目的,许多人发现它很有用。ResourcelessTransactionManager
和相关类已在 v4 中弃用,并已安排
在 v5 中删除。如果要使用内存中作业存储库,可以使用嵌入式数据库
如 H2、Apache Derby 或 HSQLDB。有几种方法可以创建嵌入式数据库并在
您的 Spring Batch 应用程序。一种方法是使用 Spring JDBC 中的 API:
在应用程序上下文中将嵌入式数据源定义为 bean 后,应选择它
如果使用 ,则自动启动 。否则,您可以使用
基于 JDBC,如 配置 JobRepository 部分所示。 |
存储库中的非标准数据库类型
如果您使用的数据库平台不在受支持平台列表中,则
如果 SQL 变体足够接近,则可能能够使用支持的类型之一。待办事项
这样,您可以使用 RAW 而不是命名空间快捷方式和
使用它来将 Database type (数据库类型) 设置为最接近的匹配项。JobRepositoryFactoryBean
以下示例演示如何使用 设置数据库类型
到 XML 中最接近的匹配项:JobRepositoryFactoryBean
<bean id="jobRepository" class="org...JobRepositoryFactoryBean">
<property name="databaseType" value="db2"/>
<property name="dataSource" ref="dataSource"/>
</bean>
以下示例演示如何使用 设置数据库类型
到 Java 中最接近的匹配项:JobRepositoryFactoryBean
// This would reside in your BatchConfigurer implementation
@Override
protected JobRepository createJobRepository() throws Exception {
JobRepositoryFactoryBean factory = new JobRepositoryFactoryBean();
factory.setDataSource(dataSource);
factory.setDatabaseType("db2");
factory.setTransactionManager(transactionManager);
return factory.getObject();
}
(尝试
如果未指定,则从 the 中自动检测数据库类型。平台之间的主要区别是
主要由递增主键的策略负责,因此
通常,可能还需要覆盖 (使用标准的
来自 Spring Framework 的实现)。JobRepositoryFactoryBean
DataSource
incrementerFactory
如果连这都不起作用,或者您没有使用 RDBMS,那么
唯一的选项可能是实现
on 上,并以正常的 Spring 方式手动连接一个。Dao
SimpleJobRepository
配置 JobLauncher
使用 时,将为您提供开箱即用的 a。
本节介绍如何配置您自己的。@EnableBatchProcessing
JobRegistry
该接口最基本的实现是 .
它唯一需要的依赖项是 ,以便获得执行。JobLauncher
SimpleJobLauncher
JobRepository
以下示例显示了 XML 格式:SimpleJobLauncher
<bean id="jobLauncher"
class="org.springframework.batch.core.launch.support.SimpleJobLauncher">
<property name="jobRepository" ref="jobRepository" />
</bean>
以下示例显示了 Java 中的一个:SimpleJobLauncher
...
// This would reside in your BatchConfigurer implementation
@Override
protected JobLauncher createJobLauncher() throws Exception {
SimpleJobLauncher jobLauncher = new SimpleJobLauncher();
jobLauncher.setJobRepository(jobRepository);
jobLauncher.afterPropertiesSet();
return jobLauncher;
}
...
获取 JobExecution 后,它会传递给
execute 方法,最终将 返回给调用者,如图所示
在下图中:Job
JobExecution
该序列简单明了,从计划程序启动时效果很好。然而
尝试从 HTTP 请求启动时出现问题。在这种情况下,启动
需要异步完成,以便立即返回到其
访客。这是因为让 HTTP 请求保持打开状态并不是一个好的做法
长时间运行的进程(如 BATCH)所需的时间。下图显示了
示例序列:SimpleJobLauncher
可以通过配置 .SimpleJobLauncher
TaskExecutor
下面的 XML 示例显示了配置为立即返回的 XML:SimpleJobLauncher
<bean id="jobLauncher"
class="org.springframework.batch.core.launch.support.SimpleJobLauncher">
<property name="jobRepository" ref="jobRepository" />
<property name="taskExecutor">
<bean class="org.springframework.core.task.SimpleAsyncTaskExecutor" />
</property>
</bean>
下面的 Java 示例显示了配置为立即返回的 Java:SimpleJobLauncher
@Bean
public JobLauncher jobLauncher() {
SimpleJobLauncher jobLauncher = new SimpleJobLauncher();
jobLauncher.setJobRepository(jobRepository());
jobLauncher.setTaskExecutor(new SimpleAsyncTaskExecutor());
jobLauncher.afterPropertiesSet();
return jobLauncher;
}
spring 接口的任何实现都可用于控制 Job 的异步方式
执行。TaskExecutor
运行 Job
启动批处理作业至少需要两件事:要启动的作业和 .两者都可以包含在同一个
context 或不同的上下文。例如,如果从
命令行中,将为每个 Job 实例化一个新的 JVM,因此每个
job 将拥有自己的 .但是,如果
从 Web 容器内运行,通常有一个 ,配置为异步作业
launching,则多个请求将调用该请求来启动其作业。Job
JobLauncher
JobLauncher
HttpRequest
JobLauncher
从命令行运行 Job
对于希望从企业运行其作业的用户 scheduler 中,命令行是主界面。这是因为 大多数调度器(Quartz 除外,除非使用 NativeJob)直接与操作系统一起使用 进程,主要由 shell 脚本启动。有很多方法 启动除 shell 脚本之外的 Java 进程,例如 Perl、Ruby 或 甚至是 Ant 或 Maven 等“构建工具”。但是,因为大多数人 熟悉 shell 脚本,本示例将重点介绍它们。
The CommandLineJobRunner
因为启动作业的脚本必须启动 Java
Virtual Machine 中,需要有一个具有 main 方法的类
作为主要入口点。Spring Batch 提供了一个实现
,它正好达到这个目的:。需要注意的是
这只是引导应用程序的一种方式,但有
启动 Java 进程的方法有很多种,这个类绝不应该是
被视为确定的。执行四项任务:CommandLineJobRunner
CommandLineJobRunner
-
加载适当的
ApplicationContext
-
将命令行参数解析为
JobParameters
-
根据参数找到合适的作业
-
使用 application context 启动作业。
JobLauncher
所有这些任务都是仅使用参数完成的 传入。以下是必需的参数:
jobPath (作业路径) |
将用于
创建一个 .此文件
应包含运行完整
工作 |
jobName (作业名称) |
要运行的作业的名称。 |
这些参数必须与路径 first 和名称 second 一起传入。所有参数 在这些参数被视为作业参数后,将转换为 JobParameters 对象, 并且必须采用 'name=value' 格式。
以下示例显示了作为作业参数传递给在 XML 中定义的作业的日期:
<bash$ java CommandLineJobRunner endOfDayJob.xml endOfDay schedule.date(date)=2007/05/05
以下示例显示了作为作业参数传递给 Java 中定义的作业的日期:
<bash$ java CommandLineJobRunner io.spring.EndOfDayJobConfiguration endOfDay schedule.date(date)=2007/05/05
默认情况下,它使用 a 隐式地将
用于标识作业参数的键/值对。但是,可以显式指定
哪些作业参数正在标识,哪些不是,分别在它们前面加上 或 前缀。 在以下示例中, is 标识作业参数 while is not:
可以使用自定义 . |
在大多数情况下,您可能希望使用 manifest 在 jar 中声明您的主类,但是,
为简单起见,该类被直接使用。此示例使用相同的 'EndOfDay'
来自 domainLanguageOfBatch 的示例。第一个
参数是 'endOfDayJob.xml',它是包含 .第二个参数 'endOfDay' 表示作业名称。最后一个参数
'schedule.date(date)=2007/05/05')转换为 JobParameters 对象。Job
以下示例显示了 in XML 的示例配置:endOfDay
<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.SimpleJobLauncher" />
在大多数情况下,您希望使用 manifest 在 jar 中声明您的主类,但是,
为简单起见,该类被直接使用。此示例使用相同的 'EndOfDay'
来自 domainLanguageOfBatch 的示例。第一个
参数是 'io.spring.EndOfDayJobConfiguration',这是完全限定的类名
添加到包含 Job 的配置类中。第二个参数 'endOfDay' 表示
作业名称。最后一个参数 'schedule.date(date)=2007/05/05' 被转换为对象。java 配置的示例如下:JobParameters
以下示例显示了 在 Java 中的配置示例:endOfDay
@Configuration
@EnableBatchProcessing
public class EndOfDayJobConfiguration {
@Autowired
private JobBuilderFactory jobBuilderFactory;
@Autowired
private StepBuilderFactory stepBuilderFactory;
@Bean
public Job endOfDay() {
return this.jobBuilderFactory.get("endOfDay")
.start(step1())
.build();
}
@Bean
public Step step1() {
return this.stepBuilderFactory.get("step1")
.tasklet((contribution, chunkContext) -> null)
.build();
}
}
前面的示例过于简单,因为
通常在 Spring Batch 中运行批处理作业,但它用于显示两个主要的
的要求 : 和 .CommandLineJobRunner
Job
JobLauncher
退出代码
从命令行启动批处理作业时,企业
经常使用 scheduler。大多数调度程序都相当愚蠢,只能工作
在流程级别。这意味着他们只知道一些
操作系统进程,例如他们正在调用的 shell 脚本。
在这种情况下,与调度程序通信的唯一方法
关于作业的成功或失败是通过返回代码。一个
return code 是进程返回给调度程序的数字
,这表示运行的结果。在最简单的情况下:0 是
成功,1 是失败。但是,可能还有更复杂的
scenarios:如果作业 A 返回 4 kick off 作业 B,并且如果它返回 5 kick
下班 C。这种类型的行为在调度程序级别配置,
但重要的是,像 Spring Batch 这样的处理框架
提供一种方法来返回 'Exit Code' 的数字表示形式
对于特定的批处理作业。在 Spring Batch 中,这是封装的
在 中,在 more
详情见第 5 章。为了讨论退出代码,
唯一需要知道的是,an 有一个 exit code 属性,该属性是
设置,并作为从 .将转换此字符串值
到一个号码:ExitStatus
ExitStatus
JobExecution
JobLauncher
CommandLineJobRunner
ExitCodeMapper
public interface ExitCodeMapper {
public int intValue(String exitCode);
}
an 的基本协定是,给定一个字符串 exit
code 时,将返回一个数字表示形式。默认的
Job Runner 使用的实现是返回 0 表示完成、1 表示一般错误和 2 表示任何作业的实现
运行器错误,例如无法在提供的上下文中找到 A。如果有更多
complex 的 3 个值,则自定义
接口的实现
必须提供。因为 是创建
an ,因此不能是
'wired together' 时,任何需要覆盖的值都必须是
自动装配。这意味着,如果在 、
在创建上下文后,它将被注入到 runner 中。都
需要做的是提供你自己的
作为根级 Bean 进行加载,并确保它是
跑步者。ExitCodeMapper
SimpleJvmExitCodeMapper
Job
ExitCodeMapper
CommandLineJobRunner
ApplicationContext
ExitCodeMapper
BeanFactory
ExitCodeMapper
ApplicationContext
从 Web 容器中运行作业
从历史上看,离线处理(例如批处理作业)一直是
从命令行启动,如上所述。但是,有
在许多情况下,从 启动
一个更好的选择。许多此类用例包括报告、临时作业
running 和 Web 应用程序支持。因为根据定义,批处理作业
运行时间长,但最关心的是确保启动
job 异步:HttpRequest
在这种情况下,控制器是 Spring MVC 控制器。更多
有关 Spring MVC 的信息,请访问:https://docs.spring.io/spring/docs/current/spring-framework-reference/web.html#mvc。
控制器启动一个 using 一个,该 a 已配置为异步启动,该
立即返回一个 .可能仍在运行,但是,这个
非阻塞行为允许控制器立即返回,这
在处理 .一
示例如下:Job
JobLauncher
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());
}
}
高级元数据使用
到目前为止,和 接口都是
讨论。它们共同表示 Simple Launch of a Job 和 basic
批处理域对象的 CRUD 操作:JobLauncher
JobRepository
A 使用 创建新对象并运行它们。 和实现
以后对基本更新使用相同的
在 Job 运行期间执行相同的执行。
基本操作足以用于简单的场景,但需要大量操作
具有数百个批处理作业和复杂调度的环境
requirements,则需要对元数据进行更高级的访问:JobLauncher
JobRepository
JobExecution
Job
Step
JobRepository
和 接口,将要讨论
下面,添加了用于查询和控制 meta 的附加功能
数据。JobExplorer
JobOperator
查询存储库
在任何高级功能之前,最基本的需求是能够
查询存储库中的现有执行。此功能是
由 interface 提供:JobExplorer
public interface JobExplorer {
List<JobInstance> getJobInstances(String jobName, int start, int count);
JobExecution getJobExecution(Long executionId);
StepExecution getStepExecution(Long jobExecutionId, Long stepExecutionId);
JobInstance getJobInstance(Long instanceId);
List<JobExecution> getJobExecutions(JobInstance jobInstance);
Set<JobExecution> findRunningJobExecutions(String jobName);
}
从上面的方法签名中可以明显看出,是
的 ,并且与 一样,它可以通过使用
工厂 Bean:JobExplorer
JobRepository
JobRepository
以下示例显示了如何在 XML 中配置 a:JobExplorer
<bean id="jobExplorer" class="org.spr...JobExplorerFactoryBean"
p:dataSource-ref="dataSource" />
以下示例演示如何在 Java 中配置 a:JobExplorer
...
// This would reside in your BatchConfigurer implementation
@Override
public JobExplorer getJobExplorer() throws Exception {
JobExplorerFactoryBean factoryBean = new JobExplorerFactoryBean();
factoryBean.setDataSource(this.dataSource);
return factoryBean.getObject();
}
...
在本章前面,我们注意到表前缀
的 可以修改以允许不同的版本或架构。因为
适用于相同的表,它也需要能够设置前缀。JobRepository
JobExplorer
以下示例演示如何在 XML 中设置 a 的表前缀:JobExplorer
<bean id="jobExplorer" class="org.spr...JobExplorerFactoryBean"
p:tablePrefix="SYSTEM."/>
以下示例显示了如何在 Java 中为 a 设置表前缀:JobExplorer
...
// This would reside in your BatchConfigurer implementation
@Override
public JobExplorer getJobExplorer() throws Exception {
JobExplorerFactoryBean factoryBean = new JobExplorerFactoryBean();
factoryBean.setDataSource(this.dataSource);
factoryBean.setTablePrefix("SYSTEM.");
return factoryBean.getObject();
}
...
JobRegistry (作业注册表)
A (及其父接口 )不是必需的,但可以是
如果要跟踪上下文中可用的作业,则很有用。它也是
在创建作业时,用于在应用程序上下文中集中收集作业
其他位置(例如,在子上下文中)。自定义实施也可以
用于操作已注册作业的名称和其他属性。
框架只提供了一个实现,它基于一个简单的
从 Job Name 映射到 Job Instance。JobRegistry
JobLocator
JobRegistry
以下示例显示了如何包含 for a for a job defined in XML:JobRegistry
<bean id="jobRegistry" class="org.springframework.batch.core.configuration.support.MapJobRegistry" />
以下示例显示了如何包含 for a job defined in Java:JobRegistry
使用 时,将为您提供开箱即用的 a。
如果要配置自己的:@EnableBatchProcessing
JobRegistry
...
// This is already provided via the @EnableBatchProcessing but can be customized via
// overriding the getter in the SimpleBatchConfiguration
@Override
@Bean
public JobRegistry jobRegistry() throws Exception {
return new MapJobRegistry();
}
...
有两种方法可以自动填充 a:使用
Bean 后处理器并使用 registrar 生命周期组件。这些
以下各节介绍了两种机制。JobRegistry
JobRegistryBeanPostProcessor
这是一个 bean 后处理器,可以在创建所有作业时注册它们。
以下示例显示了如何为 job 添加
在 XML 中定义:JobRegistryBeanPostProcessor
<bean id="jobRegistryBeanPostProcessor" class="org.spr...JobRegistryBeanPostProcessor">
<property name="jobRegistry" ref="jobRegistry"/>
</bean>
以下示例显示了如何为 job 添加
在 Java 中定义:JobRegistryBeanPostProcessor
@Bean
public JobRegistryBeanPostProcessor jobRegistryBeanPostProcessor() {
JobRegistryBeanPostProcessor postProcessor = new JobRegistryBeanPostProcessor();
postProcessor.setJobRegistry(jobRegistry());
return postProcessor;
}
尽管并非绝对必要,但 example 已被赋予一个 ID,以便它可以包含在 child 中 上下文(例如,作为父 bean 定义)并导致创建所有作业 那里也会自动注册。
AutomaticJobRegistrar
这是一个生命周期组件,用于创建子上下文并从中注册作业
上下文。这样做的一个好处是,虽然
子上下文在 Registry 中仍然必须是全局唯一的,它们的依赖项
可以有 “natural” 名称。例如,您可以创建一组 XML 配置文件
每个 Job 只有一个 Job,但都具有不同的 an 定义,其中
相同的 bean 名称,例如 “reader”。如果所有这些文件都导入到同一上下文中,则
Reader 定义会相互冲突并覆盖,但使用 Automatic
registrar 这是避免的。这使得集成 Job 贡献
应用程序的单独模块。ItemReader
以下示例显示了如何包含定义的 for a job defined
在 XML 中:AutomaticJobRegistrar
<bean class="org.spr...AutomaticJobRegistrar">
<property name="applicationContextFactories">
<bean class="org.spr...ClasspathXmlApplicationContextsFactoryBean">
<property name="resources" value="classpath*:/config/job*.xml" />
</bean>
</property>
<property name="jobLoader">
<bean class="org.spr...DefaultJobLoader">
<property name="jobRegistry" ref="jobRegistry" />
</bean>
</property>
</bean>
以下示例显示了如何包含定义的 for a job defined
在 Java 中:AutomaticJobRegistrar
@Bean
public AutomaticJobRegistrar registrar() {
AutomaticJobRegistrar registrar = new AutomaticJobRegistrar();
registrar.setJobLoader(jobLoader());
registrar.setApplicationContextFactories(applicationContextFactories());
registrar.afterPropertiesSet();
return registrar;
}
registrar 有两个必需的属性,一个是数组(此处从
方便的 Factory Bean),另一个是 .负责管理子上下文的生命周期,并且
在 中注册作业。ApplicationContextFactory
JobLoader
JobLoader
JobRegistry
的
负责创建子上下文和最常见的用法
将如上所述,使用 .其中之一
这个工厂的特点是,默认情况下它会复制一些
configuration down 从 parent context 到 child。所以对于
实例中,您不必重新定义 AOP
配置,如果它应该与
父母。ApplicationContextFactory
ClassPathXmlApplicationContextFactory
PropertyPlaceholderConfigurer
可用于
如果需要,与 a 结合使用(只要
使用)。例如,如果有工作,这可能是可取的
在主父上下文和子上下文中定义
地点。AutomaticJobRegistrar
JobRegistryBeanPostProcessor
DefaultJobLoader
JobOperator (作业操作员)
如前所述,它提供对元数据的 CRUD 操作,并且 提供对
元数据。但是,这些操作在一起使用时最有用
执行常见监控任务,例如停止、重新启动或
总结 Job,这通常是由 Batch Operator 完成的。Spring Batch
通过接口提供以下类型的操作:JobRepository
JobExplorer
JobOperator
public interface JobOperator {
List<Long> getExecutions(long instanceId) throws NoSuchJobInstanceException;
List<Long> getJobInstances(String jobName, int start, int count)
throws NoSuchJobException;
Set<Long> getRunningExecutions(String jobName) throws NoSuchJobException;
String getParameters(long executionId) throws NoSuchJobExecutionException;
Long start(String jobName, String parameters)
throws NoSuchJobException, JobInstanceAlreadyExistsException;
Long restart(long executionId)
throws JobInstanceAlreadyCompleteException, NoSuchJobExecutionException,
NoSuchJobException, JobRestartException;
Long startNextInstance(String jobName)
throws NoSuchJobException, JobParametersNotFoundException, JobRestartException,
JobExecutionAlreadyRunningException, JobInstanceAlreadyCompleteException;
boolean stop(long executionId)
throws NoSuchJobExecutionException, JobExecutionNotRunningException;
String getSummary(long executionId) throws NoSuchJobExecutionException;
Map<Long, String> getStepExecutionSummaries(long executionId)
throws NoSuchJobExecutionException;
Set<String> getJobNames();
}
上述操作表示来自许多不同接口的方法,例如 、 、 和 。因此,
提供的 , , 具有许多依赖项。JobLauncher
JobRepository
JobExplorer
JobRegistry
JobOperator
SimpleJobOperator
以下示例显示了 XML 中的典型 bean 定义:SimpleJobOperator
<bean id="jobOperator" class="org.spr...SimpleJobOperator">
<property name="jobExplorer">
<bean class="org.spr...JobExplorerFactoryBean">
<property name="dataSource" ref="dataSource" />
</bean>
</property>
<property name="jobRepository" ref="jobRepository" />
<property name="jobRegistry" ref="jobRegistry" />
<property name="jobLauncher" ref="jobLauncher" />
</bean>
以下示例显示了 Java 中的典型 bean 定义:SimpleJobOperator
/**
* All injected dependencies for this bean are provided by the @EnableBatchProcessing
* infrastructure out of the box.
*/
@Bean
public SimpleJobOperator jobOperator(JobExplorer jobExplorer,
JobRepository jobRepository,
JobRegistry jobRegistry,
JobLauncher jobLauncher) {
SimpleJobOperator jobOperator = new SimpleJobOperator();
jobOperator.setJobExplorer(jobExplorer);
jobOperator.setJobRepository(jobRepository);
jobOperator.setJobRegistry(jobRegistry);
jobOperator.setJobLauncher(jobLauncher);
return jobOperator;
}
如果您在作业存储库上设置了表前缀,请不要忘记在作业资源管理器中也设置它。 |
JobParametersIncrementer (作业参数增量器)
上的大多数方法都是
不言自明,更详细的解释可以在界面的 Javadoc 上找到。但是,该方法值得注意。这
method 将始终启动 Job 的新实例。
如果 a 和 Job 中存在严重问题,这可能非常有用
需要从头开始。但与此不同的是,它需要一个新对象,如果参数与
任何前面的参数集,该方法都会使用 Tied to 来强制 to 一个
新建实例:JobOperator
startNextInstance
JobExecution
JobLauncher
JobParameters
JobInstance
startNextInstance
JobParametersIncrementer
Job
Job
public interface JobParametersIncrementer {
JobParameters getNext(JobParameters parameters);
}
的合约是
给定一个 JobParameters 对象,它将返回“下一个”JobParameters
object 来增加它可能包含的任何必要值。这
策略很有用,因为框架无法知道
更改 Make it the 'next'
实例。例如,如果 中的唯一值是 date,并且 next 实例
应该创建,该值是否应该增加一天?或者一个
周(例如,如果工作是每周)?任何
有助于识别 Job 的数值,
如下所示:JobParametersIncrementer
JobParameters
JobParameters
public class SampleIncrementer implements JobParametersIncrementer {
public JobParameters getNext(JobParameters parameters) {
if (parameters==null || parameters.isEmpty()) {
return new JobParametersBuilder().addLong("run.id", 1L).toJobParameters();
}
long id = parameters.getLong("run.id",1L) + 1;
return new JobParametersBuilder().addLong("run.id", id).toJobParameters();
}
}
在此示例中,键为“run.id”的值用于
区分。如果传入的值为 null,则可以为
假设 以前从未运行
因此可以返回其初始状态。但是,如果不是,则旧的
value 被获取,递增 1 并返回。JobInstances
JobParameters
Job
对于以 XML 定义的作业,可以通过
'incrementer' 属性,如下所示:Job
<job id="footballJob" incrementer="sampleIncrementer">
...
</job>
对于用 Java 定义的作业,可以通过构建器中提供的方法将增量程序与 'Job' 相关联,如下所示:incrementer
@Bean
public Job footballJob() {
return this.jobBuilderFactory.get("footballJob")
.incrementer(sampleIncrementer())
...
.build();
}
停止作业
最常见的用例之一是正常停止
工作:JobOperator
Set<Long> executions = jobOperator.getRunningExecutions("sampleJob");
jobOperator.stop(executions.iterator().next());
关闭不是立即的,因为没有办法强制
立即关闭,尤其是在执行当前处于
开发人员代码,例如
商业服务。但是,一旦控制权返回到
框架中,它会将当前状态设置为 ,保存它,然后执行相同的操作
对于整理前。StepExecution
BatchStatus.STOPPED
JobExecution
中止作业
任务执行可以是
restarted (如果 是可重启的)。状态为 的任务执行 将不会被框架重新启动。
状态也用于步骤
执行以在重新启动的任务执行中将其标记为可跳过:如果
作业正在执行,并遇到在上一个失败的作业执行中标记的步骤,则
将进入下一步(由 Job Flow 定义确定
和步骤执行退出状态)。FAILED
Job
ABANDONED
ABANDONED
ABANDONED
如果进程已终止( 或服务器
failure),该作业当然不会运行,但
无法知道,因为在过程结束之前没有人告诉它。你
必须手动告诉它您知道执行失败
或应被视为已中止(将其状态更改为 或 )。这是
一个商业决策,没有办法自动化它。更改
status 设置为仅当它是可重启的并且您知道重启数据有效时。kill -9
JobRepository
FAILED
ABANDONED
FAILED