Spring Batch学习记录

什么是Spring Batch

Spring Batch是Spring 的一个子项目,是一款基于Spring的企业批处理框架,是一个轻量级的、全面的批处理框架。
Spring Batch提供了可重用的功能,不仅提供了统一的读写接口、丰富的任务处理方式、灵活的事务管理以及并发处理,同时还支持日志、监控、任务重启玉跳过等特性。

为什么要使用Spring Batch以及应用的场景

  • 为什么要使用

    Spring Batch是基于Spring开发的很容易上手
    Spring Batch不是一个调度框架,因为它已经有非常好的企业级调度框架包括Quartz等,它只注重任务处理的相关问题,如执行任务、事务、并发等,而不是提供调度功能

  • 应用的场景
    • 周期提交批处理任务
    • 同时批处理任务:并非处理一个任务
    • 分阶段的企业消息驱动处理
    • 高并发批处理
    • 失败后的手动或定时重启
    • 按顺序处理任务依赖(使用工作流驱动的批处理插件)
    • 部分处理:跳过记录(例如:回滚)
    • 全批次事务:因为可能有小数据量的批处理或存在存储过程/脚本
  • 批处理的特点
    • 数据量大
    • 整个过程全部自动化,并预留一定接口进行自定义配置
    • 这样的应用通常是周期性运行,比如按日、周、月运行
    • 对数据处理的准确性要求高,并且需要容错机制、回滚机制、完善的日志监控等

Spring Batch的处理原则

1. 尽量使用公用模块
2. 尽量简化操作,不要有复杂的业务逻辑,更不要处理一条数据还要调用外部接口进行数据加工
3. 尽可能少的IO操作
4. 同一个批处理文件不要处理两次
5. 尽可能压力测试

Spring Batch的结构

Spring Batch分三层:应用层、核心层和基础架构层
应用层: 开发人员使用Spring Batch编写的所有批处理任务代码
核心层: 包含加载和控制批处理作业所需的核心类,Job,Step等类的实现
基础架构层: 包含统用的读写器和重试模块

batch流程

在这里插入图片描述

Spring batch框架有4个主要组件:JobLauncher、Job、Step和JobRepository。
	1)JobLauncher(任务启动器):通过它启动任务,可以理解为程序的入口。
	2)Job(任务):一个具体的任务。
	3)Step(步骤):一个具体的执行步骤,一个Job中可以有多个Step。
	4)JobRepository(任务仓库):存储数据的仓库,在任务执行的时候,需要用它来记录任务状态信息,可以看做是一个数据库的接口。
	JobLauncher启动Job,Job可以有多个Step组合,每个Step有开发者自己编写
	每一个Step对应一个ItemReader、ItemProcessor和ItemWriter
	
job : 任务
  一个job可以由一个或多个step组成,通过JobBuilderFactory实例创建Bean,使用next指向下一个step;

flow:  
   1.是多个step的集合;
   2.可以被多个Job复用;
   3.由flowBuilder来创建的;

split:
     实现并发执行;


批处理框架简单抽象成:读取数据、处理数据、写数据
Spring Batch提供了三个接口: ItemReader、ItemProcessor、ItemWriter
JobRepository是记录Job、Step和发起Job的执行信息

Step的处理流程

Spring Batch的核心概念

  • 什么是JobLauncher

    JobLauncher是任务启动器,该接口只有一个run方法

    public interface JobLauncher {
        public JobExecution run(Job job, JobParameters jobParameters)
                throws JobExecutionAlreadyRunningException, JobRestartException,
                JobInstanceAlreadyCompleteException, JobParametersInvalidException;
    }
    

    除了传入Job对象外,还需要传入JobParameters对象,通过JobLauncher可以在java程序中调用批处理任务,也可以通过命令行或者其他框架(如定时调度框架Quartz、Web后台框架Spring MVC)中调用批处理任务

  • 什么是JOB

    Job是一个封装整个批处理过程的概念,体现在代码中是最上层的一个接口
    Job的实现类主要有两种:一个是simplejob,另一个是flowjob
    一个Job是我们运行的基本单位,它内部由Step组成,Job实质上是Step的一个容器,

    @Bean
    public Job footballJob(){
        return jobBuilderFactory.get("footballJob")
                .start(firstStep())
                .next(secondStep())
                .build();
    }
    配置的意思是:首先给Job起一个名字footballJob,接着指定这个Job的两个Step(有几个Step指定几个,也可以灵活指定),他们分别由方法firstStep()secondStep()实现
    
  • 什么是JobInstance

    JobInstance指的是逻辑单元的概念,考虑一个批作业,不仅仅执行一次,所以对每个作业的运行必须单独逻辑的JobInstance跟踪,而且每个JobInstance可以多个执行,并且在给定时间内相同参数的同一个JobInstance只能有一个能运行。

    JobInstance的定义与要加载的数据完全没有关系

  • 什么是JobParameters

    同一个Job每天运行一次的话,每天也就都有一个JobInstance,但是如何区分JobInstance呢?那么就是JobParameters

    JobParameters对象包含一组用于启动批处理作业的参数,它在运行期间用于识别或者用作参考数据。
    JobInstance =Job + JobParameters
    JobInstance

  • 什么是JobExecution

    JobExecution作为一个Job一次执行任务的上下文,因为Job的一个JobInstance有可能失败而多次执行,这样就需要一个上下文来管理同一个JobInstance的多次执行,一次执行有可能失败或成功结束,只有JobExecution执行成功JobInstance才被认为是完成了。

  • 什么是Step

    Step是一个领域对象,它体现了批处理作业的独立的、连续的阶段。一个Step可以简单也可以复杂,一个简单的步骤可能会将数据从文件加载到数据库中,只需要很少或根本不需要代码,更复杂的步骤可能有作为处理一部分应用的复杂业务规则。与Job一样,Step也有独立的StepExecution存储每一个Step的执行信息。

    Step流程

  • 什么是StepExecution

    StepExecution表示一次执行Step,每次运行一个Step时都会创建一个新的StepExecution,类似与JobExecution,但是某个步骤可能由于其之前的步骤失败而无法执行,且仅当Step实际启动时才会创建StepExecution。

    StepExecution 用来表示每一个step 的执行。每个StepExecution都包含对其相应step和与JobExecution以及事务相关数据的引用,比如提交和回滚计数以及开始和结束时间。此外,每个步骤执行都包含一个ExecutionContext,它包含开发人员在批处理运行期间需要持久化的任何数据,例如重新启动所需的统计信息或状态信息。

  • 什么是ExecutionContext

    ExecutionContext即每一个StepExecution 的执行环境。它包含一系列的键值对。我们可以用如下代码获取ExecutionContext

    ExecutionContext ecStep = stepExecution.getExecutionContext();
    ExecutionContext ecJob = jobExecution.getExecutionContext();
    
    
  • 什么是JobRepository

    JobRepository是一个用于将上述job,step等概念进行持久化的一个类。 它同时给Job和Step以及下文会提到的JobLauncher实现提供CRUD操作。 首次启动Job时,将从repository中获取JobExecution,并且在执行批处理的过程中,StepExecution和JobExecution将被存储到repository当中。

    @EnableBatchProcessing注解可以为JobRepository提供自动配置。

  • 什么是JobLauncher

    JobLauncher这个接口的功能非常简单,它是用于启动指定了JobParameters的Job,为什么这里要强调指定了JobParameter,原因jobparameter和job一起才能组成一次job的执行

    public interface JobLauncher {
        public JobExecution run(Job job, JobParameters jobParameters)
                throws JobExecutionAlreadyRunningException, JobRestartException,
                JobInstanceAlreadyCompleteException, JobParametersInvalidException;
    }
    
  • 什么是Item Reader

    ItemReader是一个读数据的抽象,它的功能是为每一个Step提供数据输入。 当ItemReader以及读完所有数据时,它会返回null来告诉后续操作数据已经读完。Spring Batch为ItemReader提供了非常多的有用的实现类,比如JdbcPagingItemReader,JdbcCursorItemReader等等。
    ItemReader包括各种类型的数据库,文件,数据流,等等

    JdbcPagingItemReader必须指定一个PagingQueryProvider,负责提供SQL查询语句来按分页返回数据

    下面是一个JdbcCursorItemReader的例子代码:
    	private JdbcCursorItemReader<Map<String, Object>> buildItemReader(final DataSource dataSource, String tableName,
            String tenant) {
    
        JdbcCursorItemReader<Map<String, Object>> itemReader = new JdbcCursorItemReader<>();
        itemReader.setDataSource(dataSource);
        itemReader.setSql("sql here");
        itemReader.setRowMapper(new RowMapper());
        return itemReader;
    }
    
  • 什么是Item Writer

    ItemReader是读数据的一个抽象,那么ItemWriter自然就是一个写数据的抽象,它是为每一个step提供数据写出的功能。写的单位是可以配置的,我们可以一次写一条数据,也可以一次写一个chunk的数据,关于chunk下文会有专门的介绍。ItemWriter对于读入的数据是不能做任何操作的。

  • 什么是Item Processor

    ItemReader是读数据的一个抽象,那么ItemWriter自然就是一个写数据的抽象,它是为每一个step提供数据写出的功能。写的单位是可以配置的,我们可以一次写一条数据,也可以一次写一个chunk的数据,关于chunk下文会有专门的介绍。ItemWriter对于读入的数据是不能做任何操作的。

  • 什么是Chunk

    由于我们一次batch的任务可能会有很多的数据读写操作,因此一条一条的处理并向数据库提交的话效率不会很高,因此spring batch提供了chunk这个概念,我们可以设定一个chunk size,spring batch 将一条一条处理数据,但不提交到数据库,只有当处理的数据数量达到chunk size设定的值得时候,才一起去commit.

    @Bean
    public Job footballJob(){
        return jobBuilderFactory.get("footballJob")
                .start(Step1())
                .build();
    }
    @Bean
    public Step Step1() {
        return stepBuilderFactory.get("Step1")
                .chunk(10)
                .reader(itemReader())
                .writer(itemWriter())
                .build();
    }
    在上面这个step里面,chunk size被设为了10,当ItemReader读的数据数量达到10的时候,
    这一批次的数据就一起被传到itemWriter,同时transaction被提交。
    

    Tasklet 与chunk 的区别

    Tasklet 意味着在step中执行单个任务,job有多个step按一定顺序组成,每个步骤应该执行一个具体任务。
    我们的job有三个步骤:
    a.从输入csv文件读
    b.对每个输入行数据计算年龄
    c.写姓名和年龄至输出csv文件

    Chunk 方法该方法基于数据块(一部分数据)执行。也就是说,其不是一次读、处理和写所有行,而是一次仅读、处理、写固定数量记录。然后重复循环执行直到读不到数据为止。
    因此,此流程与上面有些差异:
    while 有数据:
    do X 行数据
    读一行
    处理一行
    写 X 行数据

    Tasklet 与chunk 总结:

    两者差异显示了各自适用场景。tasklet更适合一个步骤到另一个步骤场景。chunk提供简单解决方案:实现处理分页读,或我们不想在内存中保留大量数据场景。

Spring Batch小案例

Spring Batch完整入门实践

Spring Batch 入门级示例教程

参考文档

Spring Batch参考文档中文版

spring batch 理解、特点、使用场景、结构 简单介绍

Spring Batch 文档和手册(中文)

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章