2016-03-26 18:46 870人阅读 评论(1) 收藏 举报
 分类:
Spring(6) 

版权声明:本文为博主原创文章,未经博主允许不得转载。

 

目录(?)[+]

 

第四章 配置作业Job

4.1 基本配置

Job的配置有3个必须的属性,name,jobRepository,steps。一个简单的Job配置如下:

<job id="footballJob">
<step id="playerload" parent="s1" next="gameLoad"/>
<step id="gameLoad" parent="s2" next="playerSummarization"/>
<step id="playerSummarization" parent="s3"/>
</job>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 1
  • 2
  • 3
  • 4
  • 5

jobRepository默认引用名称为jobRepository的bean,当然也可以显式地配置:

<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>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 1
  • 2
  • 3
  • 4
  • 5
4.1.1 Restartable属性

该属性定义Job是否可以被重启,默认为true,在JobExecution执行失败后,可以创建另一个JobExecution来继续上次的执行。但是如果该属性设为false,重新执行该JobInstance将抛出异常。

<job id="footballJob" restartable="false">
...
</job>
  • 1
  • 2
  • 3
  • 1
  • 2
  • 3
4.1.2 拦截Job执行

spring Batch在Job的生命周期中提供了一些钩子方法,可这些钩子方法通过Listener的形式提供。JobListener的接口定义如下:

public interface JobExecutionListener {

    void beforeJob(JobExecution jobExecution);

    void afterJob(JobExecution jobExecution);

}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

通过实现JobExecutionListener接口并配置给Job,可以在Job执行前后执行特定的逻辑。例如在执行结束之后,如果失败,发送邮件通知管理人员等。

<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>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

需要注意的是,无论Job是否成功执行,afterJob方法都会执行,Job是否执行成功,可以从JobExecution中获取。

public void afterJob(JobExecution jobExecution){
if( jobExecution.getStatus() == BatchStatus.COMPLETED ){
//job success
}
else if(jobExecution.getStatus() == BatchStatus.FAILED){
//job failure
}
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

Listener的执行顺序: 
beforeJob与配置的顺序一样,afterJob与配置的顺序相反。

Listener异常: 
Listener的执行过程中如果抛出异常,将导致Job无法继续完成,最终状态为FAILED.因此要合理控制Listener异常对业务的影响。

注解支持: 
如果不想使用侵入性强的Listener接口,可以使用@BeforeJob和@AfterJob两个注解声明。

4.1.3 Job抽象与继承

通用的Job配置可以抽取出来,作为抽象的Job存在,抽象的Job不允许被实例化:

<job id="baseJob" abstract="true">
<listeners>
<listener ref="listenerOne"/>
<listeners>
</job>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 1
  • 2
  • 3
  • 4
  • 5

子Job可以通过继续共用这些配置(当然,也可以继承非抽象的Job)。

<job id="job1" parent="baseJob">
<step id="step1" parent="standaloneStep"/> <listeners merge="true">
<listener ref="listenerTwo"/>
<listeners>
</job>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

其中的merge=”true”表示合并父job和子job的配置,也就是两个Listener都生效,同常规的Spring配置。

4.1.4 Job参数验证

JobParameterValidator组件用于验证JobParameter。通过以下配置为job配置验证器:

<job id="job1" parent="baseJob3">
<step id="step1" parent="standaloneStep"/>
<validator ref="paremetersValidator"/>
</job>
  • 1
  • 2
  • 3
  • 4
  • 1
  • 2
  • 3
  • 4
4.1.4 属性的Late Binding

在Spring中,可以把Bean配置用到的属性值通过PropertiesPlaceHolderConfiguer把属性从配置中分离出来独立管理,理论上来说,在配置Job的时候也可以使用相同的方式。但是Spring Batch提供了在运行时配置参数值的能力:

<bean:property name="filePath" value="#{jobParameters['filePath']}" />
  • 1
  • 1

在启动Job时:

    launcher.executeJob("job.xml" , "footjob",
new JobParametersBuilder().addDate("day", new Date()))
.addString("filePath", "/opt/data/test.xml"));
  • 1
  • 2
  • 3
  • 1
  • 2
  • 3

4.2 配置JobRepository

JobRepository为任务框架中的各个组件对象提供CRUD操作,例如JobExecution,StepExecution。 
一个配置例子如下:

<job-repository id="jobRepository"
data-source="dataSource"
transaction-manager="transactionManager"
isolation-level-for-create="SERIALIZABLE"
table-prefix="BATCH_"
max-varchar-length="1000"/>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
4.2.1 事务配置

JobRepository的操作需要事务来保证其完整性以及正确性,这些元数据的完整性对框架来说非常重要。如果没有事务支持,框架的行为将无法正确定义。 
create*方法的事务隔离级别单独定义,为了保证同一个JobInstance不会被同时执行两次,默认的隔离级别为SERIALIZABLE,可以被修改:

<job-repository id="jobRepository"
isolation-level-for-create="REPEATABLE_READ" />
  • 1
  • 2
  • 1
  • 2

如果没有使用Batch命名空间或者没有使用Factory Bean,则需要显示配置事务AOP:

<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>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
4.2.2 表名前缀

默认情况下,Spring Batch需要的表以BATCH作为前缀,不过可以自定义:

<job-repository id="jobRepository"
table-prefix="e_batch" />
  • 1
  • 2
  • 1
  • 2

表前缀可以修改,但是表名和表的列不能被修改。

4.2.3 特殊的Repository

测试环境中,内存级别的数据库十分方便:

<bean id="jobRepository"
class="org.springframework.batch.core.repository.support.MapJobRepositoryFactoryBean">
<property name="transactionManager" ref="transactionManager"/>
</bean>
  • 1
  • 2
  • 3
  • 4
  • 1
  • 2
  • 3
  • 4

如果使用的数据库类型不在SpringBatch的支持中,可以通过JobRepositoryFactoryBean自定义。

4.3 配置JobLauncher

默认提供了一个简单的Launcher:

<bean id="jobLauncher"
class="org.springframework.batch.core.launch.support.SimpleJobLauncher">
<property name="jobRepository" ref="jobRepository" />
</bean>
  • 1
  • 2
  • 3
  • 4
  • 1
  • 2
  • 3
  • 4

JobLauncher的时序图如下:

如果启动的请求来自HTTP,那么等待整个Job完成再返回不是一个好方法,此时需要异步启动Job,时序图如下:

相应的Launcher配置如下:

<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>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

4.4 运行Job

有多种方式可以启动一个Job,但是核心都是通过JobLauncher来实现。 
1. 命令行运行 
主要通过CommandLineJobRunner类完成

2. 从Web容器中运行 
通过Http请求启动任务很常见,时序图如下: 

Controller可以是常规的Spring MVC Controller:

@Controller
public class JobLauncherController { @Autowired
JobLauncher jobLauncher; @Autowired
Job job; @RequestMapping("/jobLauncher.html")
public void handle() throws Exception{
jobLauncher.run(job, new JobParameters());
}
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

3. 使用调度框架运行 
可以与其他调度框架一起使用,例如使用Spring的轻量级调用框架Spring Scheduler或者Quartz

4.5 元数据的高级用法

除了通过JobRepository对元数据进行CRUD操作外,Spring batch还提供另外的接口用于访问元数据。 
包括: JobExplorer JobOperator。整体结构如下: 

4.5.1 JobExplorer

该组件提供了只读的查询操作,是JobRepository的只读版本,接口定义如下:

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);
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

配置一个Bean如下:

<bean id="jobExplorer" class="org.spr...JobExplorerFactoryBean"
p:dataSource-ref="dataSource" />
  • 1
  • 2
  • 1
  • 2

如果需要制定表名前缀:

<bean id="jobExplorer" class="org.spr...JobExplorerFactoryBean"
p:dataSource-ref="dataSource" p:tablePrefix="BATCH_" />
  • 1
  • 2
  • 1
  • 2
4.5.2 JobOperator

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(); }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33

配置:

<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>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

其中的startNextInstance方法将使用当前Job的JobParameter,经过JobParametersIncrementer处理之后的参数启动一个JobInstance。

public interface JobParametersIncrementer {

    JobParameters getNext(JobParameters parameters);

}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 1
  • 2
  • 3
  • 4
  • 5

下面是一个简单实现:

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();
}
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

为job配置incrementer:

<job id="footballJob" incrementer="sampleIncrementer">
...
</job>
  • 1
  • 2
  • 3
  • 1
  • 2
  • 3

在每天处理一次的批处理中,Incrementer的实现可能是按日期递增。

 
1

0

Spring Batch(4): Job详解的更多相关文章

  1. Spring Data操作Redis详解

    Spring Data操作Redis详解 Redis是一种NOSQL数据库,Key-Value形式对数据进行存储,其中数据可以以内存形式存在,也可以持久化到文件系统.Spring data对Redis ...

  2. elasticSearch+spring 整合 maven依赖详解

    摘自:http://www.mayou18.com/detail/nTxPQSyu.html [Elasticsearch基础]elasticSearch+spring 整合 maven依赖详解 Ma ...

  3. Spring Aop底层原理详解

    Spring Aop底层原理详解(来源于csdn:https://blog.csdn.net/baomw)

  4. Spring Boot 自定义日志详解

    本节内容基于 Spring Boot 2.0. 你所需具备的基础 什么是 Spring Boot? Spring Boot 核心配置文件详解 Spring Boot 开启的 2 种方式 Spring ...

  5. Java Spring cron表达式使用详解

    Java Spring cron表达式使用详解   By:授客 QQ:1033553122 语法格式 Seconds Minutes Hours DayofMonth Month DayofWeek ...

  6. Spring RestController 请求参数详解

    Spring RestController 请求参数详解 引用作者jpfss 在阅读之前,最好先了解http请求的get,post,以及各种head头类型,请求参数类型. 无参数,设置RestCont ...

  7. spring框架 AOP核心详解

    AOP称为面向切面编程,在程序开发中主要用来解决一些系统层面上的问题,比如日志,事务,权限等待,Struts2的拦截器设计就是基于AOP的思想,是个比较经典的例子. 一 AOP的基本概念 (1)Asp ...

  8. Spring定时器corn表达式详解

    1.结构 Spring定时器corn表达式详解 2.各字段的含义 字段 允许值 允许的特殊字符 秒 0~59 - * / 分 0~59 - * / 小时 0~23 - * / 日期 1~31 - * ...

  9. Spring Cloud限流详解

    转自:https://blog.csdn.net/tracy38/article/details/78685707 在高并发的应用中,限流往往是一个绕不开的话题.本文详细探讨在Spring Cloud ...

随机推荐

  1. Node.js:Web 模块

    ylbtech-Node.js:Web 模块 1.返回顶部 1. Node.js Web 模块 什么是 Web 服务器? Web服务器一般指网站服务器,是指驻留于因特网上某种类型计算机的程序,Web服 ...

  2. Python基本数据类型之字典dict

    字典dict 是一个键(key)值(value)对,结构为{},大括号 创建字典 ? 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 info = { # k ...

  3. 爬虫中之Requests 模块的进阶

    requests进阶内容 session处理cookie proxies参数设置请求代理ip 基于线程池的数据爬取 引入 有些时候,我们在使用爬虫程序去爬取一些用户相关信息的数据(爬取张三“人人网”个 ...

  4. Ubuntu16.04系统下汉字显示为方框解决办法(图文详解)

    不多说,直接上干货! 问题详情 问题分析 今天一打开Ubuntu系统,竟然不支持中文显示了.开始时以为是搜狗拼音的问题,然后重装了一遍fcitx,然后用重装了一遍搜狗输入法.可是重装后问题根本没有解决 ...

  5. jQuery Validate前端验证

    我们经常看到如下效果,那么它是如何实现的呢?看下面: 废话少说,直接上代码,大家直接Copy就能看到上面的效果啦. <html> <head> <title>验证内 ...

  6. sql创建表

    表的创建 1.创建列(字段):列名+类型 2.设置主键列:能够唯一表示一条数据 3.设置唯一键:设计--索引/键--添加--唯一键(选择列)--确定 唯一键的内容不能重复 4.外键关系:一张表(从表) ...

  7. Monad的重点

    Monad是非常强有力的概念,在介绍Monad是什么和如何工作的之前,我们应该先确认Monad能解决什么问题.Monad是各种编程问题的的 meta solution,它不是某种特定问题的解决方案,我 ...

  8. CI中的验证码

    CI中的验证码相对来说使用非常方便直接加载类调用函数以及一些配置,代码如上,比较简单,具体函数可在CI手册的辅助函数参考CAPTCHA辅助函数中查询,CI中的验证码是直接生成验证码图片在你自己创建的C ...

  9. (转)RabbitMQ学习之Headers交换类型(java)

    http://blog.csdn.net/zhu_tianwei/article/details/40923131 Headers类型的exchange使用的比较少,它也是忽略routingKey的一 ...

  10. js 读取外部的本地json文件

    Javascript 读取外部的本地json文件 方案1 运行本地web服务器,提供文件服务 方案2 1.data = '[{"name" : "Ashwin" ...