springboot整合springbatch

余生长醉 提交于 2019-12-29 20:02:17

springbatch几个概念

springbatch是一个用于进行批处理数据的轻量级框架,用于后台批量执行一些大数据相关的任务,和spring无缝整合

先来看看官方的一张关于springbatch的架构图
在这里插入图片描述

  • Job 任务
  • Step 任务里包含的步骤
  • ItemReader 单个步骤里的输入(input)
  • ItemProccesor input的处理
  • ItemWriter 单个步骤里的输出(output)

ItemReader,ItemProccesor,ItemWriter这个类似于java 8里funtional编程

spring batch 主要对象介绍

对象 描述
job 作业。批处理中的核心概念,是Batch操作的基础单元
JobInstance 作业实例。每个作业执行时,都会生成一个实例,实例会被存放在JobRepository中,如果作业失败,下次重新执行该作业时,会使用同一个作业实例。对于Job和JobInstance的关系,可以理解为Java中类和实例对象的关系。
JobParameters 作业参数。它是一组用来启动批处理任务的参数,在启动Job的时候,可以设置任何需要的作业参数。需要注意的是作业参数会用来标识作业实例,即不同的Job实例是通过Job参数的来区分的。
JobExecution 作业执行器。负责具有Job的执行,每次运行Job都回启动一个新的Job执行器。
-JobRepository- -作业仓库。主要负责存储作业执行过程中的状态数据和结果。为JobLauncher、Job、Step提供标准的CRUD实现-
JobLauncher 作业调度器(任务启动器)。它根据给定的JobParameters执行作业。
Step 作业步(操作步)。Job的一个执行环节,多个或者一个Step组成Job,封装了批处理任务中的一个独立的连续阶段。
-StepExecution- 作业步执行器。负责具体Step的执行。每次运行Step都会启动一个新的执行器
Tasklet Tasklet。step中具体执行逻辑的操作。可以重复执行。可以设置具体的同步、异步操作等。
ExecutionContext 执行上下文。它是一组框架持久化与控制的key/value对,能够让开发者在StepExecution或JobExecution范畴保存需要进行持久化的状态。
-Item- 条目。一条数据记录。
Chunk Item集合。它是给定数量Item的集合。可以定义对读操作、处理操作、写操作,提交间隔等
ItemReader 条目读(读操作)。表示Step读取数据,一次读取一条数据。
ItemProcessor 条目处理(处理操作)。用于表示Item的业务处理。
ItemWriter 条目写(写操作)。用于表示Step输出数据,一次输出一条。

术语解读

1. Job

  • 批处理作业Job是由一组Step组成的,同时也是作业配置文件的顶层的元素。一般每个跑批Job都会有一个配置文件,在配置文件中配置Job的内容。如:每个Job都有自己唯一的id(名字),定义Step的执行顺序,定义作业是否可以重启等 。
  • Job执行的时候会生成一个Job Instance(作业实例),Job Instance包含执行Job期间产生的数据以及Job的执行状态信息等。Job Instance是通过Job Name(作业名称)和Job Parameters(作业参数)来区分的。每次Job执行的时候都会有一个Job Execution(作业执行器),Job Execution负责具体Job的执行。
  • 一个Job可能有一个或多个Job Instance。
  • 一个Job Instance可能有一个或多个Job Execution。(如果不理解往下看)

2. Job Instance

  • Job Instance(作业实例)是一个运行期概念,Job每次执行都会涉及一个Job Instance。
  • Job Instance来源有两种可能:一种是根据设置的Job Parameters从Job Repository(作业仓库)中获取,第二中是如果根据设置的Job Parameters没有从Job Repository中获取到,则新创建一个Job Instance。

3. Job Parameters
 
一个Job通过Job Parameters来区分不同的Job Instance。如果同一个Job,Job Name一样的话,则Job Parameters肯定不一样,但是对于不同的Job来说,允许有相同的Job Parameters。也就是说Job Instance = Job Name + Job Parameters。

4.Job Execution

  • List itemJob Execution表示Job执行的句柄。一次Job的执行可能成功也可能失败,只有Job Execution执行成功时才会生成相应的Job Instance。这就是为什么一个Job Instance对应一个或多个Job Execution。
  • Job Execution对应的数据库是:BATCH_JOB_EXECUTION
  • Job Execution对应的Java类是:org.springframework.batch.core.JobExecution。
  • JobExecution主要的属性和表的字段差不多,其中属性中executionContext是:包含运行过程中所有需要被持久化的用户数据

5. Step
Step表示作业中一个完整的步骤,一个Job可以有一个或多个Step,Step包含一个实际运行的批处理任务中的所有必须处理的信息。一个Step可以有一个或多个Step Execution。当一个Job由多个Step组成时,每个Step执行都会生成一个新的Step Execution,则一个Job Execution就会拥有多个Step Execution。

比如reader、processor、writer是一个Step,合并文件是一个Step,创建信号文件是一个Step。

Step中可以配置tasklet、partition、job、flow等。

6. Step Execution

  • Step Execution是Step执行的句柄。和Job Execution相似。一个Step可以有一个或多个Step Execution。
  • Step Execution对应的数据库是:BATCH_STEP_EXECUTION
  • Step Execution对应的Java类是:org.springframework.batch.core.StepExecution。
  • Step执行的过程是由StepExecution类的对象所表示的,包括每次执行对应的step、Job Execution、相关的事务操作等,此外每次执行step时还包含一个ExecutionContext,用来存放开发者在批处理运行过程中所需要的任何信息。

7. Execution Context

Execution Context是Spring Batch框架提供的持久化与控制的key/value对,能够让开发者在Step Execution或Job Execution中保存需要进行持久化的状态。框架会在每次commit后记录当前的提交记录数和读的记录数,保证继续从上次失败的点重新执行。

Execution Context分为两类:一类是Job Execution的上下文(对应表:BATCH_JOB_EXECUTION_CONTEXT),另一类是Step Execution的上下文(对应表:BATCH_STEP_EXECUTION_CONTEXT)。两类上下文之间的关系:一个Job Execution对应一个Job Execution上下文;每个Step Execution对应一个Step Execution 上下文;同一个Job中的Step Execution 共用Job Execution上下文。因此如果同一个Job不同的Step间需要共享数据,则可以从Job Execution的上下文共享数据。

8. Job Repository

Spring Batch框架提供Job Repository来存储Job执行期的元数据(这里的元数据是指:Job Instance、Job Execution、Job Parameters、Step Execution、Execution Context等),并提供两种默认实现方式。一种是存放在内存中,一种是将元数据存放在数据库中。

上述概念虽然有点多,但是了解这些概念对使用springbatch至关重要,否则就是拿到了代码也不知从何看起,更不用说写程序了,下面使用springboot演示一下搭建一个简单springbatch项目的过程

代码整合

1、添加依赖

<parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.0.1.RELEASE</version>
        <relativePath/>
    </parent>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <java.version>1.8</java.version>
    </properties>

    <dependencies>

        <!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-batch -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-batch</artifactId>
            <version>2.2.1.RELEASE</version>
        </dependency>


        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.16.20</version>
            <scope>compile</scope>
        </dependency>
        <!--< dependency>-->
        <!--<groupId>com.h2database</groupId>-->
        <!--<artifactId>h2</artifactId>-->
        <!--</dependency>-->

        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-jpa</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-jdbc</artifactId>
        </dependency>

        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-lang3</artifactId>
            <version>3.5</version>
        </dependency>

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-oxm</artifactId>
        </dependency>

        <dependency>
            <groupId>com.thoughtworks.xstream</groupId>
            <artifactId>xstream</artifactId>
            <version>1.4.10</version>
        </dependency>

        <!-- https://mvnrepository.com/artifact/com.h2database/h2 -->
        <!--<dependency>
            <groupId>com.h2database</groupId>
            <artifactId>h2</artifactId>
        </dependency>-->

    </dependencies>
    <!-- 指定maven版本 -->
    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

自己做测试的时候可以不使用mysql连接,springbatch默认使用内存数据库h2
,这里为了模拟的更真实点儿,直接使用mysql,通过程序初始化sql脚本将springbatch运行时需要的数据表创建出来,springbatch自带的sql脚本位置为:/org/springframework/batch/core/schema-mysql.sql

2、添加配置文件

spring.datasource.driverClassName=com.mysql.jdbc.Driver
spring.datasource.url=jdbc:mysql://ip:3307/springbatch?useSSL=false
spring.datasource.username=用户名
spring.datasource.password=密码

#spring.datasource.schema=classpath:/org/springframework/batch/core/schema-mysql.sql
#
#spring.batch.initialize-schema=always

初次启动项目的时候,可以把spring.datasource.schema这段配置打开,程序连接上了数据库会自动创建表,需要提前在数据库创建一个库,我这里名称为:springbatch

3、springbatch测试类

@Configuration
@EnableBatchProcessing
public class JobConfiguration {

    @Autowired
    private JobBuilderFactory jobBuilderFactory;

    @Autowired
    private StepBuilderFactory stepBuilderFactory;

    /**
     * 程序执行的入口
     * @return
     */
    @Bean
    public Job helloJob(){
        return jobBuilderFactory.get("helloJob").start(step1()).build();
    }

    @Bean
    public Step step1() {
        return stepBuilderFactory.get("step1").tasklet(
                new Tasklet() {
                    @Override
                    public RepeatStatus execute(StepContribution stepContribution, ChunkContext chunkContext) throws Exception {
                        System.out.println("hello spring batch");
                        return RepeatStatus.FINISHED;
                    }
                }
        ).build();
    }
}

这段代码非常简单,一个被spring容器扫描到的job,一个step,这两个术语上文都有解释,这里的意思是启动一个job,这个job里面要执行一个步骤,执行的逻辑放在step的bean中完成,当然,还可以定义多个step,然后再在job里面添加进去,具体的API使用可以参考其他资料,比如下面的这个,一个job要执行两个步骤

@Configuration
@EnableBatchProcessing
public class JobFlowDemo1 {

    @Autowired
    private JobBuilderFactory jobBuilderFactory;

    @Autowired
    private StepBuilderFactory stepBuilderFactory;

    @Bean
    public Job jobFlowDemo1(){
        /*return jobBuilderFactory.get("jobFlowDemo1")
                .start(step1())
                .next(step2())
                .next(step3())
                .build();*/

        return jobBuilderFactory.get("jobFlowDemo1")
                .start(step1()).on("COMPLETED").to(step2())
                .from(step2()).on("COMPLETED").to(step3())
                .from(step3()).end().build();

    }

    @Bean
    public Step step1() {
        return stepBuilderFactory.get("step1").tasklet(
                new Tasklet() {
                    @Override
                    public RepeatStatus execute(StepContribution stepContribution, ChunkContext chunkContext) throws Exception {
                        System.out.println("hello spring batch step1");
                        return RepeatStatus.FINISHED;
                    }
                }
        ).build();
    }

    @Bean
    public Step step2() {
        return stepBuilderFactory.get("step2").tasklet(
                new Tasklet() {
                    @Override
                    public RepeatStatus execute(StepContribution stepContribution, ChunkContext chunkContext) throws Exception {
                        System.out.println("hello spring batch step2");
                        return RepeatStatus.FINISHED;
                    }
                }
        ).build();
    }

    @Bean
    public Step step3() {
        return stepBuilderFactory.get("step3").tasklet(
                new Tasklet() {
                    @Override
                    public RepeatStatus execute(StepContribution stepContribution, ChunkContext chunkContext) throws Exception {
                        System.out.println("hello spring batch step3");
                        return RepeatStatus.FINISHED;
                    }
                }
        ).build();
    }


}

4、启动类

@SpringBootApplication
public class App {

    public static void main(String[] args) {
        SpringApplication.run(App.class,args);
    }

}

启动程序,通过控制台的输出结果,可以看到当前的这个job通过设置的3个step分别执行了不同的逻辑
在这里插入图片描述

同时,程序自动会创建表,并在相关的表中插入数据,比如这个jobName即为上述程序中指定的那个jobName
在这里插入图片描述

本篇到这里就结束了,有兴趣的同学可以继续深入研究相关的API,最后感谢观看!

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!