以前两篇介绍了如何基本的使用SpringBatch,可是企业应用历来都不是单一的,一大堆看起来可气的需求和一堆难以理清的关系.也有可能你的项目尚未Release原始需求已经被改了一大半.而咱们又不肯意更改咱们写的像艺术品同样的代码,最好的状况也就是在上面加上一些逻辑,而后以热插拔的方式达到要求. java
对于前面介绍的流程也就一个Step,流程图: 正则表达式
其实SpringBatch是能够支持多个Step的.如: spring
对于上面的流程,咱们只须要多定义几个Step,使用next联系起来就能够工做了. shell
<job id="exampleJob"> <step id="StepA" next="StepB"/> <step id="StepB" next="StepC"/> <step id="StepC"/> </job>
每一个Step都一个parent属性,它和Ant的depend有点相似,至关与在执行该Step前执行parent指定的Step.如: app
<job id="exampleJob"> <step id="StepA"/> <step id="StepB" parent=”StepA” next="StepC"/> <step id="StepC"/> </job>
好了,顺序的执行永远是最简单的,咱们写程序不可能总顺序的,可不能够来个选择呢?如: ide
这个是确定没有问题的.咱们有两种方式来进行选择,一种是使用Decision标记,一种添加Listener.他们均可以凭返回值包含的字符串进行区分来进行选择流程. 测试
下面我使用Decision作个例子. ui
Tasklet是Step中被执行的一个单元,Tasklet类: this
public class DecisionTasklet implements Tasklet { private String message; public DecisionTasklet() { } @Override public RepeatStatus execute(StepContribution contribution, ChunkContext chunkContext) throws Exception { System.out.println("message is: " + message); return RepeatStatus.FINISHED; } /** * @param message * the message to set */ public void setMessage(String message) { this.message = message; }
Decisor是Step选择执行的: spa
public class JobDecider implements JobExecutionDecider { public JobDecider() { } @Override public FlowExecutionStatus decide(JobExecution jobExecution, StepExecution stepExecution) { if(stepExecution.getReadCount() < 1) { return FlowExecutionStatus.FAILED; } return FlowExecutionStatus.COMPLETED; } }
上面的代码中我 stepExecution.getReadCount() < 1,很明显,这个示例中我没有使用任何Reader,所以getReadCount()只会返回0,这里我只让他返回FAILED.一下子咱们在注释掉这段代码用于测试结果.
Spring Schama:
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:batch="http://www.springframework.org/schema/batch" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/batch http://www.springframework.org/schema/batch/spring-batch-2.1.xsd"> <import resource="applicationBatch.xml"/> <bean id="hello" class="net.dbatch.myexample.DecisionTasklet"> <property name="message" value="hello" /> </bean> <bean id="failed" class="net.dbatch.myexample.DecisionTasklet"> <property name="message" value="failed" /> </bean> <bean id="success" class="net.dbatch.myexample.DecisionTasklet"> <property name="message" value="success" /> </bean> <bean id="jobDecider" class="net.dbatch.decision.JobDecider" /> <batch:job id="decisionJob"> <batch:step id="step1" next="decision"> <batch:tasklet ref="hello" transaction-manager="transactionManager" /> </batch:step> <batch:decision id="decision" decider="jobDecider"> <batch:next on="FAILED" to="step2" /> <batch:next on="COMPLETED" to="step3" /> </batch:decision> <batch:step id="step2"> <batch:tasklet ref="failed" transaction-manager="transactionManager" /> </batch:step> <batch:step id="step3"> <batch:tasklet ref="success" transaction-manager="transactionManager" /> </batch:step> </batch:job> </beans>
请注意,我把Tasklet类在spring中注册了3次.
测试类:
public static void main(String[] args) { ApplicationContext c = new ClassPathXmlApplicationContext("decision_job.xml"); SimpleJobLauncher launcher = new SimpleJobLauncher(); launcher.setJobRepository((JobRepository) c.getBean("jobRepository")); launcher.setTaskExecutor(new SyncTaskExecutor()); try { JobExecution je = launcher.run((Job) c.getBean("decisionJob"), new JobParametersBuilder().toJobParameters()); System.out.println(je); System.out.println(je.getJobInstance()); System.out.println(je.getStepExecutions()); } catch (Exception e) { e.printStackTrace(); } }
输出:
10-22 19:47:13 INFO [job.SimpleStepHandler] - <Executing step: [step1]> message is: hello 10-22 19:47:13 INFO [job.SimpleStepHandler] - <Executing step: [step2]> message is: failed
由日志咱们能够看出由step1->step2,咱们注释掉 JobDecider类中的:
if(stepExecution.getReadCount() < 1) { return FlowExecutionStatus.FAILED; }
从新运行测试类.输出:
10-22 19:53:17 INFO [job.SimpleStepHandler] - <Executing step: [step1]> message is: hello 10-22 19:53:17 INFO [job.SimpleStepHandler] - <Executing step: [step3]> message is: success
很明显它走了step1->step3的流程.
上面讲的还有一种执行选择的流程是添加1个Listener,由于Listener只能使用chunk的方式配置Tasklet,所以示例逻辑上有点罗嗦,我不细述.
假如咱们这样的Listener:
public class SkipCheckingListener extends StepExecutionListenerSupport { public ExitStatus afterStep(StepExecution stepExecution) { String exitCode = stepExecution.getExitStatus().getExitCode(); if (!exitCode.equals(ExitStatus.FAILED.getExitCode()) && stepExecution.getSkipCount() > 0) { return new ExitStatus("COMPLETED WITH SKIPS"); } else { return null; } } }Spring配置:
<bean id="payStepCheckingListener" class="net.dbatch.sample.PayStepCheckingListener" /> <job id="job"> <step id="stepA"> <next on="COMPLETED WITH SKIPS" to="stepB" /> <next on="FAILED" to="stepC" /> <next on="*" to="otherStep" /> <listeners> <listener ref="payStepCheckingListener" /> </listeners> </step> <step id="stepB" next="stepC" /> <step id="stepC" /> </job>
next的on属性能够匹配简单的正则表达式.如:
? 能够匹配0个或一个字符
* 能够匹配0个或者多个字符
例如:"c*t"将会匹配"cat"和"count", "c?t"只能匹配"cat"可是不能匹配"count".
由Listener的返回值 ExitStatus返回的状态能够按照咱们的意愿决定下一步执行哪一个Step.