一、拦截器实现说明
1.拦截器的实现方式
Spring Batch项目实现Step级拦截器有两种方法:
(1)实现接口:org.springframework.batch.core.StepExecutionListener
public interface StepExecutionListener extends StepListener {
//Step执行之前调用该方法
void beforeStep(StepExecution var1);
//Step执行之后调用该方法
ExitStatus afterStep(StepExecution var1);
}afterStep方法执行后会返回ExitStatus,表示当次作业步执行后的推出状态。
(2)通过Annotation机制实现
- @BeforeStep
- @AfterStep
2.拦截器的配置
通过下面的方法配置拦截器:
<!--定义名字为billJob1的作业-->
<batch:job id="billJob1">
<!--定义一个Step,继承parentStep-->
<batch:step id="billStep1">
<batch:tasklet ref="myTasklet"/>
<batch:listeners>
<batch:listener ref="sysoutListener"/>
<batch:listener ref="sysoutAnnotationListener"/>
</batch:listeners><!--注入SysoutAnnotationListener拦截器-->
<bean id="sysoutAnnotationListener" class="com.xj.demo11.SysoutAnnotationListener"/>
<!--注入SysoutListener拦截器-->
<bean id="sysoutListener" class="com.xj.demo11.SysoutListener"/>
3.拦截器异常
拦截器方法如果抛出异常会影响Step的执行,所以在执行自定义的拦截器的时候,需要考虑对拦截器发生的异常做处理,避免影响业务。
如果拦截器发生异常,会导致Step执行的状态为“FAILED”;作业的状态同样为“FAILED”。
4.拦截器执行顺序
在配置文件中可以配置多个listener,拦截器之间的执行顺序按照listener定义的顺序执行。before方法按照listener定义的顺序执行,after方法按照相反的顺序执行。这个同Job级拦截器一样。比如根据上面“2.拦截器的配置”中的拦截器配置,执行顺序应该是:
(1)sysoutListener拦截器的before方法
(2)sysoutAnnotationListener拦截器的before方法
(3)sysoutAnnotationListener拦截器的after方法
(4)sysoutListener拦截器的after方法
5.merge属性
假设有这样一个场景,所有的Step都希望拦截器sysoutListener能够执行,而拦截器sysoutAnnotationListener则由每个具体的Step定义是否执行,通过抽象和继承属性可以完成上面的场景。
<!--定义抽象Step-->
<batch:step id="abstractStep" abstract="true">
<!--定义抽象Step的拦截器-->
<batch:listeners>
<batch:listener ref="sysoutListener"/>
</batch:listeners>
</batch:step>
<!--定义名字为billJob2的作业-->
<batch:job id="billJob2">
<batch:step id="billStep2" parent="abstractStep">
<batch:tasklet ref="myTasklet"/>
<!--merge=true 表示继承父Step的拦截器-->
<batch:listeners merge="true">
<!--定义billStep2的拦截器-->
<batch:listener ref="sysoutAnnotationListener"/>
</batch:listeners>
因为merge为“true”,当billStep2执行时,既会触发sysoutListener拦截器,同时又会触发sysoutAnnotationListener拦截器;否则只会触发sysoutAnnotationListener拦截器。
二、拦截器项目实现
1.项目架构

2.代码实现
Demo11BatchMain.java:
package com.xj.demo11;
import org.springframework.batch.core.Job;
import org.springframework.batch.core.JobExecution;
import org.springframework.batch.core.JobParameters;
import org.springframework.batch.core.JobParametersBuilder;
import org.springframework.batch.core.launch.JobLauncher;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
/**
* @Author : xjfu
* @Date : 2021/12/12 15:12
* @Description :Step级拦截器
*/
public class Demo11BatchMain {
public static void main(String[] args) {
Demo11BatchMain batchMain = new Demo11BatchMain();
//测试拦截器功能
batchMain.executeJob("demo11/job/demo11-job.xml", "billJob1", "jobLauncher", new JobParametersBuilder().toJobParameters());
//测试merge功能
batchMain.executeJob("demo11/job/demo11-job.xml", "billJob2", "jobLauncher", new JobParametersBuilder().toJobParameters());
}
public void executeJob(String jobXmlPath, String jobId, String jobLauncherId, JobParameters jobParameters){
ApplicationContext context = new ClassPathXmlApplicationContext(jobXmlPath);
//获得JobLauncher
JobLauncher jobLauncher = (JobLauncher) context.getBean(jobLauncherId);
//获取要执行的Job
Job job = (Job)context.getBean(jobId);
try{
//开始执行Job
JobExecution jobExecution = jobLauncher.run(job, jobParameters);
//输出执行结果
System.out.println(jobExecution.toString());
}catch (Exception e){
e.printStackTrace();
}
}
}MyTasklet.java:
package com.xj.demo11;
import org.springframework.batch.core.StepContribution;
import org.springframework.batch.core.scope.context.ChunkContext;
import org.springframework.batch.core.step.tasklet.Tasklet;
import org.springframework.batch.repeat.RepeatStatus;
/**
* @Author : xjfu
* @Date : 2021/12/12 15:37
* @Description :demo11的Tasklet
*/
public class MyTasklet implements Tasklet {
@Override
public RepeatStatus execute(StepContribution stepContribution, ChunkContext chunkContext) throws Exception {
System.out.println("demo11 的 Tasklet 执行啦!");
return RepeatStatus.FINISHED;
}
}SysoutAnnotationListener.java:
package com.xj.demo11;
import org.springframework.batch.core.ExitStatus;
import org.springframework.batch.core.StepExecution;
import org.springframework.batch.core.annotation.AfterStep;
import org.springframework.batch.core.annotation.BeforeStep;
/**
* @Author : xjfu
* @Date : 2021/12/12 15:19
* @Description :通过注解的方式实现step级拦截器
*/
public class SysoutAnnotationListener {
@BeforeStep
public void beforeStep(StepExecution stepExecution){
System.out.println("SysoutAnnotationListener————beforeStep " + stepExecution.getStartTime());
}
@AfterStep
public ExitStatus afterStep(StepExecution stepExecution){
System.out.println("SysoutAnnotationListener————afterStep " + stepExecution.getStartTime());
return null;
}
}SysoutListener.java:
package com.xj.demo11;
import org.springframework.batch.core.ExitStatus;
import org.springframework.batch.core.StepExecution;
import org.springframework.batch.core.StepExecutionListener;
/**
* @Author : xjfu
* @Date : 2021/12/12 15:18
* @Description :通过实现StepExecutionListener方式实现step级拦截器
*/
public class SysoutListener implements StepExecutionListener {
@Override
public void beforeStep(StepExecution stepExecution) {
System.out.println("SysoutListener————beforeStep " + stepExecution.getStartTime());
}
@Override
public ExitStatus afterStep(StepExecution stepExecution) {
System.out.println("SysoutListener————afterStep " + stepExecution.getStartTime());
return null;
}
}demo11-job.xml:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:batch="http://www.springframework.org/schema/batch"
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.xsd">
<!--导入文件-->
<import resource="classpath:demo11/job/demo11-jobContext.xml"/>
<!--定义名字为billJob1的作业-->
<batch:job id="billJob1">
<!--定义一个Step,继承parentStep-->
<batch:step id="billStep1">
<batch:tasklet ref="myTasklet"/>
<batch:listeners>
<batch:listener ref="sysoutListener"/>
<batch:listener ref="sysoutAnnotationListener"/>
</batch:listeners>
</batch:step>
</batch:job>
<!--定义抽象Step-->
<batch:step id="abstractStep" abstract="true">
<!--定义抽象Step的拦截器-->
<batch:listeners>
<batch:listener ref="sysoutListener"/>
</batch:listeners>
</batch:step>
<!--定义名字为billJob2的作业-->
<batch:job id="billJob2">
<batch:step id="billStep2" parent="abstractStep">
<batch:tasklet ref="myTasklet"/>
<!--merge=true 表示继承父Step的拦截器-->
<batch:listeners merge="true">
<!--定义billStep2的拦截器-->
<batch:listener ref="sysoutAnnotationListener"/>
</batch:listeners>
</batch:step>
</batch:job>
</beans>demo11-jobContext.xml:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
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">
<!--定义作业仓库 Job执行期间的元数据存储在内存中-->
<bean id="jobRepository" class="org.springframework.batch.core.repository.support.MapJobRepositoryFactoryBean">
</bean>
<!--定义作业调度器,用来启动job-->
<bean id="jobLauncher" class="org.springframework.batch.core.launch.support.SimpleJobLauncher">
<!--注入jobRepository-->
<property name="jobRepository" ref="jobRepository"/>
</bean>
<!--定义事务管理器,用于Spring Batch框架中对数据操作提供事务能力-->
<bean id="transactionManager" class="org.springframework.batch.support.transaction.ResourcelessTransactionManager"/>
<!--注入SysoutAnnotationListener拦截器-->
<bean id="sysoutAnnotationListener" class="com.xj.demo11.SysoutAnnotationListener"/>
<!--注入SysoutListener拦截器-->
<bean id="sysoutListener" class="com.xj.demo11.SysoutListener"/>
<!--注入MyTasklet-->
<bean id="myTasklet" class="com.xj.demo11.MyTasklet"/>
</beans>3.运行结果
(1)调用billJob1的执行结果:

(2)调用billJob2的执行结果,测试merge属性:

















