SpringBatch从入门到实战(三):多步骤控制

news2024/11/16 9:41:49

一:if else案例

案例:如果开始步骤成功了就执行成功步骤,否则执行失败步骤。

// 伪代码
String exitStatus = helloWorldJob();
if("FAILED".equals(exitStatus)){
    failStep();
}else{
    successStep();
}
@Configuration
public class HelloWorldJobConfig {

    @Autowired
    private JobBuilderFactory jobBuilderFactory;

    @Autowired
    private StepBuilderFactory stepBuilderFactory;


    @Bean
    public Job helloWorldJob() {
        // 执行helloWorldStep,如果成功执行successStep,否则执行failStep(helloWorldStep抛异常时算失败)
        // on()表示条判断
        return jobBuilderFactory.get("helloWorldJob")
                .start(helloWorldStep()).on("FAILED").to(failStep())
                .from(helloWorldStep()).on("*").to(successStep())
                .end()
                .incrementer(new RunIdIncrementer())
                .build();
    }


    @Bean
    public Step helloWorldStep() {
        return stepBuilderFactory.get("helloWorldStep")
                .tasklet(helloWorldTasklet())
                .build();
    }

    @Bean
    public Step successStep() {
        return stepBuilderFactory.get("successStep")
                .tasklet(successTasklet())
                .build();
    }

    @Bean
    public Step failStep() {
        return stepBuilderFactory.get("failStep")
                .tasklet(failTasklet())
                .build();
    }

    @Bean
    public Tasklet helloWorldTasklet() {
        return new Tasklet() {
            @Override
            public RepeatStatus execute(StepContribution stepContribution, ChunkContext chunkContext) throws Exception {
                System.out.println("helloWorldTasklet");
                int a = 1/0;
                return RepeatStatus.FINISHED;
            }
        };
    }


    @Bean
    public Tasklet successTasklet() {
        return new Tasklet() {
            @Override
            public RepeatStatus execute(StepContribution stepContribution, ChunkContext chunkContext) throws Exception {
                System.out.println("successTasklet");
                return RepeatStatus.FINISHED;
            }
        };
    }

    @Bean
    public Tasklet failTasklet() {
        return new Tasklet() {
            @Override
            public RepeatStatus execute(StepContribution stepContribution, ChunkContext chunkContext) throws Exception {
                System.out.println("failTasklet");
                return RepeatStatus.FINISHED;
            }
        };
    }
}
  • start(Step) 后面跟on(), on表示start()返回的退出状态ExitStatus,如果equals就执行to(Step)的逻辑。
  • 后面都是从from(Step)开始,参数表示用那个步骤的返回值与后面的on(String)做比较,eqauls为true执行to(Step)逻辑。* 表示通配符,表示else逻辑。

二:自定义on()值

  • start(Step) 后面跟next(jobExecutionDecider())。
  • from都是取作业执行决策器jobExecutionDecider返回的值与on做比较。
@Bean
public Job helloWorldJob() {
    return jobBuilderFactory.get("helloWorldJob")
            .start(helloWorldStep())
            .next(jobExecutionDecider())
            .from(jobExecutionDecider()).on("OK").to(successStep())
            .from(jobExecutionDecider()).on("*").to(failStep())
            .end()
            .incrementer(new RunIdIncrementer())
            .build();
}


@Bean
public StepExecutionListener stepExecutionListener() {
    return new HelloWorldStepListener();
}


@Bean
public Tasklet helloWorldTasklet() {
    return new Tasklet() {
        @Override
        public RepeatStatus execute(StepContribution stepContribution, ChunkContext chunkContext) throws Exception {
            System.out.println("helloWorldTasklet");
            // 不支持put chunkContext.getStepContext().getJobExecutionContext().put("code", "500");

			// 500 -> ERROR -> failStep
            ExecutionContext executionContext = chunkContext.getStepContext().getStepExecution().getJobExecution().getExecutionContext();
            executionContext.put("code", "500");
            return RepeatStatus.FINISHED;
        }
    };
}
public class MyJobExecutionDecider implements JobExecutionDecider {
    @Override
    public FlowExecutionStatus decide(JobExecution jobExecution, StepExecution stepExecution) {
        String code = jobExecution.getExecutionContext().getString("code");
        if ("200".equals(code)) {
            return new FlowExecutionStatus("OK");
        } else if ("404".equals(code)) {
            return new FlowExecutionStatus("NotFound");
        }
        return new FlowExecutionStatus("ERROR");
    }
}

三:退出状态

3.1 退出状态

public class ExitStatus implements Serializable, Comparable<ExitStatus> {

    //未知状态
	public static final ExitStatus UNKNOWN = new ExitStatus("UNKNOWN");

    //执行中
	public static final ExitStatus EXECUTING = new ExitStatus("EXECUTING");

    //执行完成
	public static final ExitStatus COMPLETED = new ExitStatus("COMPLETED");

    //无效执行
	public static final ExitStatus NOOP = new ExitStatus("NOOP");

    //执行失败
	public static final ExitStatus FAILED = new ExitStatus("FAILED");

    //编程方式主动停止
	public static final ExitStatus STOPPED = new ExitStatus("STOPPED");
}    

一般来说,作业启动之后,这些状态皆为流程自行控制。

  • 顺利结束返回:COMPLETED
  • 异常结束返回:FAILED
  • 无效执行返回:NOOP
  • 编程结束:STOPED

但是也可以通过api强制改变状态:

  • end():作业流程直接成功结束,返回状态为:COMPLETED
  • fail():作业流程直接失败结束,返回状态为:FAILED
  • stopAndRestart(step) :作业流程中断结束,返回状态:STOPPED 再次启动时,从step位置开始执行 (注意:前提是参数与Job Name一样)
//如果helloWorldStep 执行成功:下一步执行successStep 否则是failStep
@Bean
public  Job job(){
    return jobBuilderFactory.get("helloWorldJob")
            .start(helloWorldStep())
            //表示将当前本应该是失败结束的步骤直接转成正常结束--COMPLETED
            //.on("FAILED").end()  
            //表示将当前本应该是失败结束的步骤直接转成失败结束:FAILED
            //.on("FAILED").fail()  
            //表示将当前本应该是失败结束的步骤直接转成停止结束:STOPPED   里面参数表示后续要重启时, 从successStep位置开始
            .on("FAILED").stopAndRestart(successStep())
            .from(firstStep()).on("*").to(successStep())
            .end()
            .incrementer(new RunIdIncrementer())
            .build();
}

3.2 停止作业

方式一: ExitStatus.STOPPED

@Configuration
public class HelloWorldStopJobConfig {

    @Autowired
    private JobBuilderFactory jobBuilderFactory;

    @Autowired
    private StepBuilderFactory stepBuilderFactory;


    @Bean
    public Job helloWorldStopJob() {
        return jobBuilderFactory.get("helloWorldStopJob")
                .start(step1()).on("STOPPED").stopAndRestart(step1())
                .from(step1()).on("*").to(step2())
                .end()
                .incrementer(new RunIdIncrementer())
                .build();
    }


    @Bean
    public Step step1() {
        return stepBuilderFactory.get("step1")
                .tasklet(tasklet1())
                .listener(stepExecutionListener())
                // 允许执行完后,运行重启
                .allowStartIfComplete(true)
                .build();
    }

    @Bean
    public StepExecutionListener stepExecutionListener() {
        return new StopStepListener();
    }


    @Bean
    public Step step2() {
        return stepBuilderFactory.get("step2")
                .tasklet(tasklet2())
                .build();
    }


    int i = -1;
    @Bean
    public Tasklet tasklet1() {
        return new Tasklet() {
            @Override
            public RepeatStatus execute(StepContribution stepContribution, ChunkContext chunkContext) throws Exception {
                System.out.println("tasklet1");
                if (i < 0) {
                    ExecutionContext executionContext = chunkContext.getStepContext().getStepExecution().getExecutionContext();
                    executionContext.put("flag", "stop");
                }
                return RepeatStatus.FINISHED;
            }
        };
    }


    @Bean
    public Tasklet tasklet2() {
        return new Tasklet() {
            @Override
            public RepeatStatus execute(StepContribution stepContribution, ChunkContext chunkContext) throws Exception {
                System.out.println("tasklet2");
                return RepeatStatus.FINISHED;
            }
        };
    }
}


public class StopStepListener implements StepExecutionListener {

    @Override
    public void beforeStep(StepExecution stepExecution) {
        System.out.println("beforeStep");
    }

    @Override
    public ExitStatus afterStep(StepExecution stepExecution) {
        Object flag = stepExecution.getExecutionContext().get("flag");
        if ("stop".equals(flag)) {
            return ExitStatus.STOPPED;
        }
        return stepExecution.getExitStatus();
    }
}

在这里插入图片描述

在这里插入图片描述
Step1正常的RepeatStatus.FINISHED了所以status=COMPLETED,但是实际退出编码是STOPPED。
在这里插入图片描述

方式二:setTerminateOnly()

StepExecution#setTerminateOnly() 给运行中的stepExecution设置停止标记,Spring Batch 识别后直接停止步骤,进而停止流程。 这种方式更简单。

@Bean
public Job helloWorldStopJob() {
    return jobBuilderFactory.get("helloWorldStopJob")
            .start(step1())
            .next(step2())
            .incrementer(new RunIdIncrementer())
            .build();
}


@Bean
public Step step1() {
    return stepBuilderFactory.get("step1")
            .tasklet(tasklet1())
            // 允许执行完后,运行重启
            .allowStartIfComplete(true)
            .build();
}


int i = -1;
@Bean
public Tasklet tasklet1() {
    return new Tasklet() {
        @Override
        public RepeatStatus execute(StepContribution stepContribution, ChunkContext chunkContext) throws Exception {
            System.out.println("tasklet1");
            if (i < 0) {
                // 终止后
                chunkContext.getStepContext().getStepExecution().setTerminateOnly();
            }
            return RepeatStatus.FINISHED;
        }
    };
}

在这里插入图片描述

在这里插入图片描述

== 注意:使用监听器返回ExitStatus.STOPPED和使StepExecution().setTerminateOnly() 在BATCH_STEP_EXECUTION中的status字段值不一样,前者是COMPLETED后者是STOPPED。==

在这里插入图片描述

四:作业重启

一般情况下当某个作业发生异常或者终止状态时可以重启作业。

  • preventRestart() :设置作业禁止重启,重启报错:JobInstance already exists and is not restartable。
@Bean
public Job helloWorldStopJob() {
    return jobBuilderFactory.get("helloWorldStopJob")
            .preventRestart()
            .start(step1())
            .next(step2())
            .incrementer(new RunIdIncrementer())
            .build();
}
  • 设置步骤最多重启次数:startLimit(num),有些步骤可能是因为网络等问题可以通过重试解决,但如果重启一定次数后还没有解决就不允许无限的去重试。超过最大次数报错:Maximum start limit exceeded for step: step1 StartMax:3
@Bean
public Step step1() {
    return stepBuilderFactory.get("step1")
            .startLimit(3)
            .tasklet(tasklet1())
            .build();
}
  • 设置步骤运行重启 allowStartIfComplete(true),这样在执行步骤时就不是NOOP了。
@Bean
public Step step1() {
    return stepBuilderFactory.get("step1")
            .allowStartIfComplete(true)
            .tasklet(tasklet1())
            .build();
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/642557.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

01 面向对象方法的概念

面向对象方法的概念 1、什么是面向对象? 面向对象不仅仅是一种程序开发方法 使用面向对象程序设计语言 使用对象、类、继承、封装、消息等基本概念进 行编程 面向对象是一种软件方法学 如何看待软件系统与现实世界的关系 以什么观点进行求解 如何进行系统构造 2、面向对象方…

chatgpt赋能python:Python导入自己写的包详解

Python导入自己写的包详解 在Python中&#xff0c;我们可以将代码封装成包来重复利用&#xff0c;也可以将自己写的包分享给其他人使用。但是&#xff0c;在使用自己写的包时&#xff0c;如何进行导入呢&#xff1f; 什么是包&#xff1f; 在Python中&#xff0c;包是一个有…

计算机网络(更新中)

本文是个人笔记&#xff0c;都是概念&#xff0c;没基础不建议看。 绪论 计算机网络的定义 最简单的定义&#xff1a;计算机网络是一些互相连接的、自治的计算机的集合因特网&#xff08;Internet&#xff09;是“网络的网络” 计算机网络的组成&#xff08;物理组成&#x…

git从http切换到ssh

git从http切换到ssh 之前项目代码git clone的http的git地址&#xff0c;后来禁用了http协议&#xff0c;只能用ssh协议。 1. 生成ssh公钥 进入Git Bash Here, 执行以下命令 ssh-keygen -m PEM -t rsa -b 4096 -C "your.emailemail.com"一直Enter直到完成。 2. 添加…

个人对几个IDE的看法

&#xff08;说明&#xff1a;本文仅表达个人看法&#xff0c;实际上文中的几个IDE功能不同&#xff0c;不能互相取代。截图上的程序均已发布&#xff09; 个人认为一款IDE在功能完整的前提下&#xff0c;应当做到操作简便。另外&#xff0c;对缩放的兼容性也会影响观感。以下…

微服务springcloud 01 sts环境,maven管理,和springcloud简介,通用模块commons

01.使用的环境是sts和maven。 02.介绍springcloud springcloud是一个大的微服务框架。 03.Spring cloud对比Dubbo Dubbo Dubbo只是一个远程调用(RPC)框架;默认基于长连接,支持多种序列化格式 Spring Cloud 框架集&#xff0c;提供了一整套微服务解决方案(全家桶);基于http调用…

【数据挖掘实战】——科大讯飞:跨境广告ROI预测

&#x1f935;‍♂️ 个人主页&#xff1a;Lingxw_w的个人主页 ✍&#x1f3fb;作者简介&#xff1a;计算机科学与技术研究生在读 &#x1f40b; 希望大家多多支持&#xff0c;我们一起进步&#xff01;&#x1f604; 如果文章对你有帮助的话&#xff0c; 欢迎评论 &#x1f4a…

云服务器上使用Docker Compose创建Redis三主三从集群

一、环境 云服务器Ubuntu20.4Dokcer 24.0.2 二、步骤 目录结构是这样&#xff1a; 绿色的目录是用来存储容器中的文件&#xff0c;不需要我们手动创建&#xff0c;将路径配置在配置文件中即可。褐色的目录和文件需要自己手动创建。 我们一共创建7个容器&#xff1a; redis…

RabbitMq消息堆积问题及惰性队列

消息堆积问题 当生产者发送消息的速度超过了消费者处理的速度&#xff0c;就会导致队列的消息堆积&#xff0c;知道队列存储消息达到上限。最早接受的消息&#xff0c;可能就会成为死信&#xff0c;会被丢弃&#xff0c;这就是消息堆积问题。 解决消费对接问题 1.增加更多的消…

Hive执行计划之只有map阶段SQL性能分析和解读

文章目录 概述1.不带函数操作的select-from-where型简单SQL1.1执行示例1.2 运行逻辑分析1.3 伪代码解释 2.带普通函数和运行操作符的普通型SQL执行计划解读2.1 执行计划解读2.2 伪代码解释逻辑 概述 可能所有的SQLboy刚接触SQL语句的时候都是select xxx from xxx where xxx。在…

如何分析问题、找到性能瓶颈、掌握性能调优?一文讲懂性能测试

背景 当下云计算、大数据盛行的背景下&#xff0c;大并发和大吞吐量的需求已经是摆在企业面前的问题了&#xff0c;其中网络的性能要求尤为关键&#xff0c;除了软件本身需要考虑到性能方面的要求&#xff0c;一些硬件上面的优化也是必不可少的。 作为一名测试工作者&#xf…

Ubuntu18.04 离线安装gcc,g++,make依赖包

1. 离线安装背景 因为项目现场的服务器无法连接互联网&#xff0c;只有内网环境&#xff0c;但是需要安装redis和nginx&#xff0c;所以需要安装gcc,g,make等依赖包。 2. 如何获取依赖包 需要准备一台可以连接互联网的电脑&#xff08;如&#xff1a;个人电脑上的虚拟机安装一…

Java网络开发(Asynchronous异步)—— 从 Jsp 到 Ajax 的 axios 到 vue 同步请求 到 异步请求

目录 引出如果想做bilibili边看视频边评论怎么搞&#xff1f;Ajax是啥&#xff1f;& axios的语法1. Ajax&#xff08;Asynchronous JavaScript And XML&#xff09;简介2. axios语法 及其与 java后端交互&#xff08;1&#xff09;get请求&#xff08;2&#xff09;post请求…

海外社媒营销揭秘:品牌出海的关键策略与注意事项

在全球化的背景下&#xff0c;品牌出海已成为众多企业拓展市场的必然选择。而海外社媒营销作为一种有效的推广手段&#xff0c;不仅能够帮助品牌建立海外影响力&#xff0c;还可以增强品牌知名度、提高销售额。然而&#xff0c;要在海外社媒平台上实施成功的营销策略&#xff0…

网络安全零基础都能看的SQL注入

1.1 .Sql 注入攻击原理 SQL 注入漏洞可以说是在企业运营中会遇到的最具破坏性的漏洞之一&#xff0c;它也是目前被利用得最多的漏洞。要学会如何防御 SQL 注入&#xff0c;首先我们要学习它的原理。 针对 SQL 注入的攻击行为可描述为通过在用户可控参数中注入 SQL 语法&#x…

高压脉冲电源和高压放大器应用领域的区别

在之前的科普中我们讲解了高压脉冲电源和高压放大器的定义及二者区别&#xff0c;其实除此之外&#xff0c;它们在应用上也是有不同倾向性的&#xff0c;那么今天让安泰测试Agitek为大家分享高压脉冲电源和高压放大器应用领域究竟有什么不同&#xff1f; 高压脉冲电源的应用领…

躺不平摆不烂的测试员如何自救?

随着测试从业年龄的增加&#xff0c;毕业的概率大增&#xff0c;而机会骤减&#xff0c;从而使测试员陷入躺不平、摆不烂的状态。 相较于开发员&#xff0c;测试员是没有资格躺平的&#xff0c;毕竟测试员没可能从短短几年黄金时间&#xff0c;从工作中积累到足以躺平的财富&a…

wordpress去除分类URL的categpory

前言 在日常使用Wordpress搭建网站时&#xff0c;发现文章或者分类页的URL地址中默认带有Category&#xff0c;URL层级过长会影响我们网站SEO的优化&#xff0c;也不利于用户体验。这里讲一下如何去除URL中categpory的方法。 操作 第一步先登录到WordPress后台&#xff0c;然…

前端样式网站(前端css框架)

1. Bootstrap:Bootstrap The most popular HTML, CSS, and JS library in the world.Bootstrap 是最流行的 CSS 框架,提供了丰富的前端样式和组件,非常适合开发响应式网站和应用程序。 2. Bulma:Bulma: Free, open source, and modern CSS framework based on FlexboxBulma 是…

nodejs 版本切换(windows版)

一、按健winR弹出窗口&#xff0c;键盘输入cmd,然后敲回车。然后进入命令控制行窗口&#xff0c;并输入where node查看之前本地安装的node的路径。 二、找到上面找到的路径&#xff0c;将node.exe所在的父目录里面的所有东西都删除。 三、从官网下载安装包 https://github.com/…