spring batch之三 配置和运行Job

本文基于spring batch reference 第四章 

Configuring and Running a Job

在spring batch之一 域模型中我们讨论了spring batch 的原型.

4.1. 配置一个job

配置一个job,只需要三个必要的依赖: 一个名字,JobRepository , 和一列steps.


    
    
    

上面的例子使用一个父Bean定义去创建step.Xml命名空间默认引用一个id 是'jobRepository' job repository。'jobRepository' 大小区分大小写。 然而,我们也可以明确定义job repository: 

job-repository="specialRepository">
    
    
    

4.1.1. 重启能力

当一个job不能被restart的时候,只需要将 restartable 属性设置成 'false'.一个job instance和job parameter相关,每次在启动job时传入的参数的值相同,可以认为同一个job instance. 我们可以将运行job的当前时间作为一个参数传入,这样子每次启动都是不同的job instance.

restartable="false">
    ...

启动一个restartable=false的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
}

上面的测试代码段显示第一次创建一个restartable=false 的job的JobExecution是没有问题的. 第二次将会抛出JobRestartException.

4.1.2. 解析job execution

我们可以实现job listener接口,在job运行前和运行后加入自己的一些逻辑.

public interface JobExecutionListener {

    void beforeJob(JobExecution jobExecution);

    void afterJob(JobExecution jobExecution);

}

JobListeners can be added to a SimpleJob via the listeners element on the job:


    
    
    
    
        
    

应该注意到不管job正常结束还是异常结束afterJob接口都会被调用. 我们需要从JobExecution获取job的结束状态.

public void afterJob(JobExecution jobExecution){
    if( jobExecution.getStatus() == BatchStatus.COMPLETED ){
        //job success
    }
    else if(jobExecution.getStatus() == BatchStatus.FAILED){
        //job failure
    }
}

对应这个接口的 annotations :

  • @BeforeJob

  • @AfterJob

4.1.3. 从一个父job中继承

如果一组jobs分享一些类似的但不同的配置.我们可以定义一个父job.类似于class的继承,子job将会结合自身的和父job的元素和属性.

下面的例子, "baseJob"是一个抽象的 Job 定义,只包含了一个listen 列表. Job "job1" 从"baseJob"中继承了listener列表并和自己的listener列表合并到一起.


    
        
    



    

    
        
    

4.1.4. job 参数验证.

可以配置一个job parameter validator 验证job parameter的正确性. 有个一个默认的实现: DefaultJobParametersValidator,我们可以参考或者使用默认实现验证job parameter. 


    
    

4.2. 配置 JobRepository

job repository 保存spring batch job的运行信息,对spring batch的自带表进行基本的CRUD操作。 请参考下面的配置: 配置数据源,事务管理器,事务隔离级别,table prefix(可以使用默认).


4.3.1. job repository的事务配置

如果使用了命名空间(batch自身的命名空间), 会自动创建事务性的advice. 这能确保元数据的正确性. 默认的事务的隔离级别对create* 方法是SERIALIZABLE,非常严格: READ_COMMITTED 就应该工作的很好; READ_UNCOMMITTED 也可以,如果不是同时启动一个job. 因为调用create*非常短 t,  SERIALIZED 不太可能会产生问题, 只要数据库平台支持SERIALIZED 事务级别. 我们也可以重写: 

isolation-level-for-create="REPEATABLE_READ" />

使用aop命名空间配置:


    
    



    
        
    

4.3.2. 改变table 前缀

默认的spring batch 自带的表都以BATCH_开头,当然我们可以改变这个前缀. table-prefix配置的前缀必须和database中的表的前缀相同.

table-prefix="SYSTEM.TEST_" />

4.3.3. 在内存中的Job Repository

spring提供了一个内存版本的job repository. 在做一些测试或者不需要保存job 运行状态的情况下,我们使用内存版的job repository.


    

内存版的job repository因为不能保存job的运行信息,有很多缺陷,在很多高级应用-跨JVM(跨机器)中不能使用.

4.4. 配置一个 JobLauncher

最简单的JobLauncher 接口的实现是 SimpleJobLauncher. 他只需要一个 JobRepository:


    

一旦获得 JobExecution ,JobExecution将会被传入job的执行方法. 最终返回 JobExecution 给调用者.

一个同步调用的顺序图. 我们可以通过一个scheduler调用spring batch.尽量不要使用http,因为batch运行时间长,会阻塞连接.

我们可以配置一个TaskExecutor实现Sim上图的异步调用:


    
    
        
    

4.5. 运行job

运行job最少的条件需要一个job和一个job launcher. 

4.5.1. 从命令行运行job

调度系统中最常用的一种方式,例如使用quartz,或使用shell脚本.

4.5.1.1. The CommandLineJobRunner

 spring 提供了一个实现类CommandLineJobRunner.这仅仅是一种从command line启动spring batch的方法.  类CommandLineJobRunner 执行了四个任务:

  • 装载 ApplicationContext

  • 传递line command 参数给JobParameters

  • 根据参数定位具体的job

  • 使用JobLauncher运行job.

所有的这些任务都是通过传递的参数完成. 下面是必须的参数:

Table 4.1. CommandLineJobRunner 参数

jobPath spring application context 的xml文件路径
jobName job 的名称

jobPath jobName 必须作为第一个和第二个参数.作为job paramete的参数必须以'name=value'的格式传递.

bash$ java CommandLineJobRunner endOfDayJob.xml endOfDay schedule.date(date)=2007/05/05

    



4.5.1.2. 退出代码

一个ExitStatus将会作为JobExecution的一部分从JobLauncher返回. CommandLineJobRunner使用一个ExitCodeMapper接口将string转换为int类型:

public interface ExitCodeMapper {

    public int intValue(String exitCode);

}

ExitCodeMapper 的默认实现是 SimpleJvmExitCodeMapper,0 代表结束, 1 代表通用错误, 2  代表job调用者错误. 

4.5.2. 在web容器中运行job

通常在web容器中以http的方式调用spring batch job,spring batch job都是以异步的方式执行.

controller是一个spring mvc 的control.. controller 使用JobLauncher 异步启动一个job, JobLauncher立即返回JobExecution. Job 会继续运行。 

@Controller
public class JobLauncherController {

    @Autowired
    JobLauncher jobLauncher;

    @Autowired
    Job job;

    @RequestMapping("/jobLauncher.html")
    public void handle() throws Exception{
        jobLauncher.run(job, new JobParameters());
    }
}

4.6. 高级的元数据的使用

到现在为止,已经讨论过JobLauncher 和 JobRepository. 

JobLauncher 使用 JobRepository 去创建新的 JobExecution 对象并运行. 在job中后续的Job 和 Step 的实现使用同样的JobRepository 作为基本的CRUD操作. 基本的操作在一些简单的场景中足够了,但是在许多batch job的复杂调度环境中,访问元数据是必须的:

4.6.1. Querying the Repository

在任何高级的特性之前,最基本的功能室查询repository了解当前的执行状态. 这些功能是由 JobExplorer 接口提供的:

public interface JobExplorer {

    List getJobInstances(String jobName, int start, int count);

    JobExecution getJobExecution(Long executionId);

    StepExecution getStepExecution(Long jobExecutionId, Long stepExecutionId);

    JobInstance getJobInstance(Long instanceId);

    List getJobExecutions(JobInstance jobInstance);

    Set findRunningJobExecutions(String jobName);
}

从上面的方法的签名中可以得知, JobExplorer 是 JobRepository的一个只读的版本, 像 JobRepository, 它可以很简单的通过一个工厂bean配置:

带table prefix的配置:

p:tablePrefix="BATCH_" />

4.6.2. JobRegistry

JobRegistry 不是必须的, 但是它可以帮助你了解有多少job在spring context中.  spring framework提供了一个唯一的实现,配置如下:

有两中方法自动填充job mapping,一种是使用一个spring bean post processor,另一种使用一种注册的有生命周期的组件:

4.6.2.1. JobRegistryBeanPostProcessor

这是一个 bean post-processor 可以注册所有的以创建的job:


    

4.6.2.2. AutomaticJobRegistrar

这是一个生命周期组件,创建子contexts并从这些子contexts中注册job。


   
      
         
      
   
   
      
         
      
   

注册器需要两个必要的属性,一个是 ApplicationContextFactory 数组,另外一个是JobLoader. JobLoader 负责管理子contexts的生命周期,并注在obRegistry中注册job.

ApplicationContextFactory 负责创建子 context,最常用的是使用 ClassPathXmlApplicationContextFactory. 一个特性之一是它会从父context中拷贝一些配置到子context中.所以不需要再子context中重新定义PropertyPlaceholderConfigurer 或者 AOP 配置,他会继承父context.

4.6.3. JobOperator

 sping batch 提供了JobOperator对batch 操作进行重启,总结,停止操作.

public interface JobOperator {

    List getExecutions(long instanceId) throws NoSuchJobInstanceException;

    List getJobInstances(String jobName, int start, int count)
          throws NoSuchJobException;

    Set 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 getStepExecutionSummaries(long executionId)
          throws NoSuchJobExecutionException;

    Set getJobNames();

}

上面的操作代表了来自不同接口的方法, 比如JobLauncherJobRepositoryJobExplorer, 和 JobRegistry. 基于这个原因,JobOperator的默认实现SimpleJobOperator有很多依赖:


    
        
            
        
    
    
    
    

4.6.4. JobParametersIncrementer

JobOperator 中的大多数方法是自解释的. 但是 startNextInstance 总是启动一个新的 Job实例. 如果当一个job在开始阶段发生了严重的错误,需要再次重启的时候,这个方法非常有用. 不像JobLauncher需要一些不同的job 参数才能重启一个job实例. startNextInstance 方法将使用 JobParametersIncrementer 试图强制重启一个新的实例:

public interface JobParametersIncrementer {

    JobParameters getNext(JobParameters parameters);

}

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();
    }
}
incrementer="sampleIncrementer">
    ...

4.6.5. 停止一个job

大多数情况下使用JobOperator 停止一个job:

Set executions = jobOperator.getRunningExecutions("sampleJob");
jobOperator.stop(executions.iterator().next());  

这段代码不能立即停止job运行,当业务逻辑把控制权返回给spring batch framework的时候,他会设置 StepExecution 的状态为 BatchStatus.STOPPED, 保存它, 然后对 JobExecution 。

4.6.6. Aborting a Job

状态为 FAILED的job 可以被重启. 状态为ABANDONED 的不能重启. The ABANDONED 也被用在step executions 标记setp execution是可以跳过的,在一个重启的job中. 如果一个job碰到一个step 在上次的执行中被标记为ABANDONED ,它将跳到下一步.

如果线程死了 ("kill -9" 或者其他错误),job 实例不能知道他的运行状态.你必须手动的告诉他失败了或者aborted. 把他的状态修改为 FAILED 或者 ABANDONED . 如果job不能被重启的话,就把他的状态修改为 FAILED


你可能感兴趣的:(spring batch之三 配置和运行Job)