Spring Batch之Step级拦截器实现(十三)

本文详细介绍了如何在SpringBatch中实现Step级拦截器,包括通过接口和注解两种方式配置,并探讨了异常处理、执行顺序及merge属性的使用。通过Demo项目展示了配置步骤和运行结果实例。
部署运行你感兴趣的模型镜像

一、拦截器实现说明

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>
    </batch:step>
</batch:job>

<!--注入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>
    </batch:step>

因为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属性:

 

您可能感兴趣的与本文相关的镜像

ACE-Step

ACE-Step

音乐合成
ACE-Step

ACE-Step是由中国团队阶跃星辰(StepFun)与ACE Studio联手打造的开源音乐生成模型。 它拥有3.5B参数量,支持快速高质量生成、强可控性和易于拓展的特点。 最厉害的是,它可以生成多种语言的歌曲,包括但不限于中文、英文、日文等19种语言

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值