spring batch(二):核心部分(2)Spring batch的启动

来源:互联网 发布:大数据利用的过程是 编辑:程序博客网 时间:2024/05/22 14:44

转自:http://kanpiaoxue.iteye.com/blog/1771208

chapter 4、Running batch jobs

 1、Spring Launch API:它的核心就是 JobLauncher 接口。

JobLauncher 的接口:

Java代码 复制代码 收藏代码
  1. public interface JobLauncher {   
  2.     public JobExecution run(Job job, JobParameters jobParameters) throws (…);   
  3. }  

 JobLauncher 需要2个参数:Job , JobParameters。

示例:

Java代码 复制代码 收藏代码
  1. ApplicationContext context = (...)   
  2. JobLauncher jobLauncher = context.getBean(JobLauncher.class);   
  3. Job job = context.getBean(Job.class);   
  4. jobLauncher.run(   
  5.     job,   
  6.     new JobParametersBuilder()   
  7.     .addString("inputFile""file:./products.txt")   
  8.     .addDate("date"new Date())   
  9.     .toJobParameters()   
  10. );  

 job的参数是key-value的键值对的形式。Spring batch提供4种类型的job参数:string,long,double,date

[注意:一个job的参数定义了一个job的实例。而一个job实例有一个或更多个的执行上下文内容。这种执行的上下文,你可以把它看作是“一次尝试执行处理过程”]

一个JobLauncher必须依赖一个Job仓库(jobRepository)

示例:

Xml代码 复制代码 收藏代码
  1. <batch:job-repository id="jobRepository" />  
  2.   
  3. <bean id="jobLauncher" class="org.springframework.batch.core.launch.support.SimpleJobLauncher">  
  4.     <property name="jobRepository" ref="jobRepository" />  
  5. </bean>  

 JobExecution 接口的示例,提供job的“运行、结束、失败”等状态的查询。

由于Job运行可能消耗非常长的时间,Spring batch同步和异步两种launcher。

异步的情况,用于类似于http请求启动job的情况。如果不是异步的启动job,会耗尽http的线程资源。

指定一个launcher是异步的,只需要给launcher的配置添加一个taskExecutor属性。

示例:

Xml代码 复制代码 收藏代码
  1. <task:executor id="executor" pool-size="10" />  
  2.   
  3. <bean id="jobLauncher" class="org.springframework.batch.core.launch.support.SimpleJobLauncher">  
  4.     <property name="jobRepository" ref="jobRepository" />  
  5.     <property name="taskExecutor" ref="executor" />  
  6. </bean>  

 

一、从命令行启动job

Triggering system ---> Creates JVM process ---> Spring Batch job

CommandLineJobRunner 是Spring batch的启动类。里面包含main函数。

运行CommandLineJobRunner的必要配置有:Spring的XML配置文件,Job,Job参数,程序退出编码。

可以把整个spring batch的项目打包成jar文件,用来运行程序。也可以指定classpath,指定CommandLineJobRunner的包中的路径来运行。

[注意:]CommandLineJobRunner是利用spring的ClassPathXmlApplicationContext来使用启动spring的,需要把spring的XML配置文件放在classpath目录内

C代码 复制代码 收藏代码
  1. java -classpath "./lib/*" org.springframework.batch.core.launch.support.CommandLineJobRunner import-products-job.xml importProductsJob inputFile=file:./products.txt date(date)=2010/12/08  

 CommandLineJobRunner 指定参数,是name=value的键值对的形式,即名字后面跟随指定的值。在指定参数的时候,可以指定参数的类型(spring batch的参数类型有:string、long、double、date),形式如下:name(type)=value  如上面的date(date)=2010/12/08 。注意date的格式是yyyy/MM/dd

Type           Java Type                                  Example

String      java.lang.String                          inputFile(string)=products.txt

Date       java.util.Date                               date(date)=2010/12/08

Long       Long                                           timeout(long)=1000

Double    Double                                       delta(double)=20.1

参数的默认类型是string,上面的 inputFile=file:./products.txt 也可以写成 inputFile(string)=file:./products.txt

 

CommandLineJobRunner是拥有运行返回值的。这个返回值默认的是:

 

Java代码 复制代码 收藏代码
  1. 0 --> The job completed successfully (COMPLETED).   
  2. 1 --> The job failed (FAILED).   
  3. 2 --> Used for errors from the command-line job runner—for example,the runner couldn’t find the job in the Spring application context.  

 当然spring batch也允许你定制这个返回值来满足不同的需求,只要实现 ExitCodeMapper 接口即可。

示例:

 

Java代码 复制代码 收藏代码
  1. import org.springframework.batch.core.ExitStatus;   
  2. import org.springframework.batch.core.launch.support.ExitCodeMapper;   
  3.   
  4. public class SkippedAwareExitCodeMapper implements ExitCodeMapper {   
  5.     @Override  
  6.     public int intValue(String exitCode) {   
  7.         if(ExitStatus.COMPLETED.getExitCode().equals(exitCode)) {   
  8.             return 0;   
  9.         } else if(ExitStatus.FAILED.getExitCode().equals(exitCode)) {   
  10.             return 1;   
  11.         } else if("COMPLETED WITH SKIPS".equals(exitCode)) {   
  12.             return 3;   
  13.         } else {   
  14.             return 2;   
  15.         }   
  16.     }   
  17. }  

 这个SkippedAwareExitCodeMapper类,该如何使用呢?把它生命在spring的XML里面靠近job就可以了,CommandLineJobRunner 会自己感知到它并且使用的。

示例:

 

Xml代码 复制代码 收藏代码
  1. <bean class="com.manning.sbia.ch04.SkippedAwareExitCodeMapper" />  
  2.   
  3. <job id="importProductsJob" xmlns="http://www.springframework.org/schema/batch">  
  4.     (...)   
  5. </job>  

 

二、Job调度

 (1)、UNIX-like的cron命令

示例:

C代码 复制代码 收藏代码
  1. 0 4 * * ? acogoluegnes java -classpath "/usr/local/bin/sb/lib/*" org.springframework.batch.core.launch.support.CommandLineJobRunner import-products-job.xml importProductsJob inputFile=file:/home/sb/import/products.txt date=2010/12/08  

 操作系统的cron命令的缺点也很明显,它会为每一个job启动一个java的进程。如果是频繁的启动job,会启动大量的java进程,消耗资源;另外,如果想在一个JVM里面启动多个job,这样job之间就可以进行内部的交互,显然这是cron做不到的。

 (2)、基于java的scheduler

 这里可以使用Quartz框架,还可以使用spring提供的task scheduler。

task scheduler的使用请参考spring reference,里面有详细的介绍。这里给出简单的例子。

java类:

Java代码 复制代码 收藏代码
  1. public class SpringSchedulingLauncher {   
  2.     private Job job;   
  3.     private JobLauncher jobLauncher;   
  4.        
  5.     public void launch() throws Exception {   
  6.         JobParameters jobParams = createJobParameters();   
  7.         jobLauncher.run(job, jobParams);   
  8.     }   
  9.        
  10.     private JobParameters createJobParameters() {   
  11.         (...)   
  12.     }   
  13.     // --- setter / getter   
  14. }  

 这里的setter/getter一定要书写,保证spring的XML能够注入属性。

使用spring的task配置调度:

Xml代码 复制代码 收藏代码
  1. <bean id="springSchedulingLauncher"  
  2.     class="com.manning.sbia.ch04.SpringSchedulingLauncher">  
  3.         <property name="job" ref="job" />  
  4.         <property name="jobLauncher" ref="jobLauncher" />  
  5. </bean>  
  6.   
  7. <task:scheduler id="scheduler" />  
  8.   
  9. <task:scheduled-tasks scheduler="scheduler">  
  10.     <task:scheduled ref="springSchedulingLauncher" method="launch" fixed-rate="1000" />  
  11. </task:scheduled-tasks>  

 

三、从web触发job

可以在使用spring的web环境配置job。通过取得http request传递过来的参数,构建JobParameter,通过JobLauncher,为每一个http request请求启动一个job。可以使用Servlet,spring MVC,structs2等框架,进行触发。

还可以在spring的web环境中配置quartz的调度,来是web拥有job的能力,不过这种方法不会响应用户http request的请求。

 

四、优雅地停止job的运行

 谁需要停止job呢?从两个角度来考虑:使用者和开发者。

(1)、使用者可能由于某些原因,需要停止job的运行,比如发现job出现数据错误,或者接到领导的命令,需要停止job的工作。

(2)、开发者。在开发程序的过程中,开发者明确的知道一些业务逻辑需要停止job。比如,一个job运行的时间不能超过早上8点,如果超过这个时间需要停止job的运行,等等的情况。

使用者,如何停止job呢?

    调用JMX或者使用spring batch administration的管理web程序,停止job

在程序中调用JMX或者使用spring batch的JobOperator接口。

也可以在spring batch里面配置简单的JobOperator,

示例:

Xml代码 复制代码 收藏代码
  1. <bean id="jobOperator" class="org.springframework.batch.core.launch.support.SimpleJobOperator">  
  2.     <property name="jobRepository" ref="jobRepository"/>  
  3.     <property name="jobLauncher" ref="jobLauncher" />  
  4.     <property name="jobRegistry" ref="jobRegistry" />  
  5.     <property name="jobExplorer" ref="jobExplorer" />  
  6. </bean>  
  7.   
  8. <batch:job-repository id="jobRepository" data-source="dataSource" />  
  9.   
  10. <bean id="jobLauncher" class="org.springframework.batch.core.launch.support.SimpleJobLauncher">  
  11.     <property name="jobRepository" ref="jobRepository" />  
  12. </bean>  
  13.   
  14. <bean class="org.springframework.batch.core.configuration.support.JobRegistryBeanPostProcessor">  
  15.     <property name="jobRegistry" ref="jobRegistry" />  
  16. </bean>  
  17.   
  18. <bean id="jobRegistry"class="org.springframework.batch.core.configuration.support.MapJobRegistry" />  
  19.   
  20. <bean id="jobExplorer" class="org.springframework.batch.core.explore.support.JobExplorerFactoryBean">  
  21.     <property name="dataSource" ref="dataSource" />  
  22. </bean>  
  23.   
  24. <bean class="org.springframework.jmx.export.MBeanExporter">  
  25.     <property name="beans">  
  26.         <map>  
  27.             <entry key="com.manning.sbia:name=jobOperator" value-ref="jobOperator" />  
  28.         </map>  
  29.     </property>  
  30. </bean>  

 

 job停止的过程的可能情况:

a、代码中的job运行的之后,检查Thread.currentThread().isInterrupted()的状态,则job会马上停止。

b、job中的程序在运行逻辑代码,只有当这些业务完成之后,程序的管理权交回到spring batch的时候,才会被终止。如果中间的业务运行需要很长的时间,则job不会马上停止。

 

开发者,如何停止job呢?

(1)、运行的过程中抛出一个exception,造成job的停止。

(2)、利用StepExecution来设置一个标识,停止job的运行。

最好的办法是,利用StepExecution来设置一个标识,停止job的运行。

代码:StepExecution.setTerminateOnly()

如何获得StepExecution 呢?

a、在Tasklet接口的方法中有StepExecution参数,可以进行调用。

示例:

Java代码 复制代码 收藏代码
  1. public class ProcessItemsTasklet implements Tasklet {   
  2.     @Override  
  3.     public RepeatStatus execute(StepContribution contribution,   
  4.             ChunkContext chunkContext) throws Exception {   
  5.         if(shouldStop()) {   
  6.             chunkContext.getStepContext().getStepExecution().setTerminateOnly();   
  7.         }   
  8.         processItem();   
  9.         if(moreItemsToProcess()) {   
  10.             return RepeatStatus.CONTINUABLE;   
  11.         } else {   
  12.             return RepeatStatus.FINISHED;   
  13.         }   
  14.         }   
  15.         (...)   
  16. }  

 

 b、面向“块”的step中,ItemReader, ItemProcessor, 和 ItemWriter 这3个接口中,你会惊奇的发现它们中间没有 StepExecution。那么你该如何在“块”Chunk中获得StepExecution 而停止程序呢?在Listener中,可以找到StepExecution。

示例:

Java代码 复制代码 收藏代码
  1. public class StopListener {   
  2.     private StepExecution stepExecution;   
  3.     @BeforeStep  
  4.     public void beforeStep(StepExecution stepExecution) {   
  5.         this.stepExecution = stepExecution;   
  6.     }   
  7.        
  8.     @AfterRead  
  9.     public void afterRead() {   
  10.         if(stopConditionsMet()) {   
  11.             stepExecution.setTerminateOnly();   
  12.         }   
  13.     }   
  14.     (...)   
  15. }  

 

spring batch 的listener的配置文件:

Xml代码 复制代码 收藏代码
  1. <bean id="stopListener" class="com.manning.sbia.ch04.stop.StopListener" />  
  2.   
  3. <batch:job id="importProductsJob">  
  4.     <batch:step id="importProductsStep">  
  5.         <batch:tasklet>  
  6.             <batch:chunk reader="reader" writer="writer" commit-interval="100"/>  
  7.             <batch:listeners>  
  8.                 <batch:listener ref="stopListener" />  
  9.             </batch:listeners>  
  10.         </batch:tasklet>  
  11.     </batch:step>  
  12. </batch:job>  

 

 [备注:] 可以把schedule调度和停止job结合起来。可以定时调用一个程序,来停止job的运行。可以把这个定时停止job的任务和spring batch放在一个spring的上下文中,在一个java进程中运行。

 从业务逻辑的需要出发,停止job的最佳的方式,还是设置stepExecution.setTerminateOnly();这个job停止标识,来让job停止运行。