Spring Batch 批处理框架

原文地址:http://blog.csdn.net/pkjxt/article/details/54584497

一、 介绍

Spring Batch能够支持简单的、复杂的和大数据量的批处理作业,是一个批处理应用框架,不是调度框架,但需要和调度框架(Quartz, Tivoli, Control-M, Cron等)合作来构建完成批处理任务。整体架构如下: 
整体架构

二、 基本概念

  1. Job: 作业, 由多个 Step 组成,封装整个批处理操作, 是 Batch 操作的基础单元;
  2. Job Instance: 作业实例,每次作业执行都会生成一个实例并存放在 JobRepository 中,如果失败,再次执行还是会用同一个作业实例;
  3. Job Parameters: 作业参数, 不同的 Job 实例是通过 Job 参数来区分的;
  4. Job Execution: 作业执行器, 负责具体 Job 的执行,每次运行 Job 都会启动一个新的 Job 执行器;
  5. Job Repository: 作业仓库, 负责储存 Job、Step 执行过程中的状态数据及结果,为 JobLauncher、Job、Step 提供标准的 CRUD 实现;
  6. Job Launchher: 作业调度器,提供执行 Job 的入口;
  7. Step: 作业步, Job 的一个执行环节,由多个或者一个 Step 组装成 Job,封装了批处理任务中的一个独立的连续阶段;
  8. Step Execution: 作业步执行器,负责具体 Step 的执行,每次运行 Step 都会启动一个新的执行器;
  9. Tasklet: Step 中具体执行逻辑的操作,可以重复执行,可以设置具体的同步、异步操作等;
  10. Execution Context: 执行上下文。它是一组框架持久化与控制的 key/value 对,能够让开发者在 Step Execution 或 Job Execution 范畴保存需要进行持久化的状态;
  11. Item: 一条数据记录;
  12. Chunk: 给定数量 Item 的集合,可以定义对 Chunk 的读操作、处理操作、写操作,提交间隔等,这是 Spring Batch 框架的一个重要特性;
  13. ItemReader: 从数据源(文件系统、数据库、队列等)中读取 Item,一次读取一条;
  14. ItemProcessor: 从 Item 写入数据源之前,对数据进行处理(如:数据清洗,数据转换,数据过滤,数据校验等);
  15. ItemWriter: 将 Item 批量写入数据源(文件系统、数据库、队列等),一次输出一批。

注意:定义 Job 基础设施: 主要配置任务仓库任务调度器和任务执行中用到的事务管理器。如下:

<bean id="jobRepository"    class="org.springframework.batch.core.repository.support.MapJobRepositoryFactoryBean" />
<bean id="jobLauncher" class="org.springframework.batch.core.launch.support.SimpleJobLauncher">
    <property name="jobRepository" ref="jobRepository" />
</bean>
<bean id="transactionManager" class="org.springframework.batch.support.transaction.ResoourcelessTransactionManager" />

三、 示例

  1. commons-batch.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:aop="http://www.springframework.org/schema/aop"
        xmlns:batch="http://www.springframework.org/schema/batch" xmlns:context="http://www.springframework.org/schema/context"
        xmlns:ehcache="http://ehcache-spring-annotations.googlecode.com/svn/schema/ehcache-spring"
        xsi:schemaLocation="
                http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.2.xsd
                http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.2.xsd
                http://www.springframework.org/schema/batch http://www.springframework.org/schema/batch/spring-batch-3.0.xsd
                http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.2.xsd
                ">
    
        <aop:aspectj-autoproxy />
        <context:component-scan base-package="com.job">
            <context:exclude-filter type="aspectj" expression="(com.job..*)" />
        </context:component-scan>
    
        <!-- 配置信息 -->
        <bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
            <property name="ignoreResourceNotFound" value="true" />
            <property name="locations">
                <list merge="true">
                    <!-- 配置数据库连接信息 -->
                    <value>classpath:databaseConfigs.properties</value>
                    <!-- 测试数据路径信息 -->
                    <value>classpath:batch-testDatas.properties</value>
                </list>
            </property>
            <property name="ignoreUnresolvablePlaceholders" value="true" />
        </bean>
    
        <!-- The DB connection -->
        <!--<import resource="classpath:db-batch.xml" />
        <import resource="classpath:db-hibernate.xml" />-->
    
        <!--<bean id="cacheManager" class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean">
            <property name="configLocation" value="classpath:ehcache.xml" />
        </bean>-->
    
        <!-- 定义 Job 基础设施 -->
        <bean id="inMemoryJobRepository" class="org.springframework.batch.core.repository.support.MapJobRepositoryFactoryBean">
            <property name="transactionManager" ref="transactionManager" />
        </bean>
        <bean id="jobLauncher" class="org.springframework.batch.core.launch.support.SimpleJobLauncher">
            <property name="jobRepository" ref="inMemoryJobRepository" />
        </bean>
    
        <!-- 定义抽象 bean -->
        <bean id="abstractJobBatch" class="com.job.batch.services.base.AbstractJobBatch" abstract="true"/>
    </beans>
  2. jobBatch.xml ( job配置 )

    <?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"
    xmlns:context="http://www.springframework.org/schema/context" xmlns:util="http://www.springframework.org/schema/util"
    xsi:schemaLocation="
        http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.2.xsd
        http://www.springframework.org/schema/batch http://www.springframework.org/schema/batch/spring-batch-3.0.xsd
        http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-4.2.xsd
        http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.2.xsd">
    
    <!-- Import of the commons -->
    <import resource="classpath:commons-batch.xml" />
    
    <!-- job start -->
    <batch:job id="jobBatch" job-repository="inMemoryJobRepository">
        <batch:step id="stepStart">
            <!--具体的start类,所指向的是下面第四点-->
            <batch:tasklet ref="jobTaskletStart" />
            <batch:next on="FAILED" to="stepFailed" />
            <batch:next on="*" to="importData" />
        </batch:step>
    
        <batch:step id="stepFailed">
            <batch:tasklet ref="jobTaskletFailed" />
        </batch:step>
    
        <batch:step id="stepCompleted">
            <batch:tasklet ref="jobTaskletCompleted" />
        </batch:step>
    
        <batch:step id="importData">
            <batch:tasklet>
                <batch:chunk reader="testReader" processor="testProcessor" writer="testWriter" commit-interval="${batch.commit.interval}" />
            </batch:tasklet>
            <batch:next on="FAILED" to="stepFailed" />
            <batch:next on="*" to="anotherStep" />
        </batch:step>
    
        <batch:step id="anotherStep">
            <batch:tasklet>
                <batch:chunk reader="anotherFileItemReader" writer="anotherFileItemWriter" commit-interval="100" >
                    <batch:streams>
                        <batch:stream ref="aaaFlatFileItemWriter"/>
                        <batch:stream ref="bbbFlatFileItemWriter"/>
                        <batch:stream ref="cccFlatFileItemWriter"/>
                    </batch:streams>
                </batch:chunk>
            </batch:tasklet>
            <batch:next on="FAILED" to="stepFailed" />
            <batch:next on="*" to="..." />
        </batch:step>
        ...
  3. AbstractJobBatch.java ( 配置抽象类的公共方法 )

    public abstract class AbstractPoiBatch{
    
        // 注入 service, 具体实现就不写了
        @Inject
        private JobBatchService jobBatchService;
    
        // 开始执行向数据库插入 log 信息
        public Integer initLogInDatabase(final String name, ...) throws jobServiceException;
    
        // 向数据库添加具体的 log 信息
        public void addLogDetail(final Integer batchId, ...) throws jobServiceException{}
    
        // 向数据库添加失败的 log 信息
        public void closeFailedLog(final Integer batchId, ...) throws jobServiceException{}
    
        // 向数据库添加成功的 log 信息
        public void closeCompletedLog(final Integer batchId, ...) throws jobServiceException{}
    
    }
  4. jobTaskletStart, (具体的开始,成功,失败的类均要实现 Tasklet 的 execute 方法)

    @Named
    public class JobTaskletStart extends AbstractJobBatch implements Tasklet {
    
        @Override
        public RepeatStatus execute(StepContribution contribution, ChunkContext chunkContext) throws Exception {
        contribution.setExitStatus(ExitStatus.COMPLETED);
        String jobName = chunkContext.getStepContext().getJobName();
        Map<String, Object> batchParameters = chunkContext.getStepContext().getJobParameters();
        Integer batchId = initLogInDatabase(jobName,...);
    
        // ExecutionContext 类: final Map<String, Object> map;
        // 所以其中可以存放jobName, batchId, timestamp, fileName...
        ExecutionContext jobExecutionContext = chunkContext.getStepContext().getStepExecution().getJobExecution().getExecutionContext();
        jobExecutionContext.put(BATCH_NAME, jobName);
    
        return RepeatStatus.FINISHED;
        }
    }
  5. testReader

    @Named("testReader")
    public class TestReader extends FlatFileItemReader<TestDto> {
    
        private ExecutionContext executionContext;
    
        @BeforeStep
        public void beforeStep(StepExecution stepExecution){
            executionContext = stepExecution.getJobExecution().getExecutionContext();
            // 读取之前的一些配置,如设置 tokenizer, lineMapper, ...
        }
    
        @Override
        protected TestDto doRead() throws SfjServiceException {
            TestDto dto = super.doRead();
            return dto;
        }
    }
  6. testProcessor

    @Named("testProcessor")
    public class TestProcessor implements ItemProcessor<TestDto, Test> {
    
        @Override
        public Test process(TestDto item) throws Exception {
            Test test = new Test();
            // 具体转换处理的步骤
            return test;
        }
    }
  7. testWriter

    @Named("testWriter")
    public class TestWriter implements ItemWriter<Test> {
        // 一般需要注入 service 来实现具体的操作
        @Inject
        private TestService testService;
    
        @BeforeStep
        public void beforeStep(StepExecution stepExecution) {
            // 执行前的操作
            ExecutionContext executionContext = stepExecution.getJobExecution().getExecutionContext();
        }
    
        @Override
        public void write(List<? extends Test> items){
            for (Test test : items) {
               // 具体的插入表操作等...
            }
        }
    
        @AfterStep
        public void afterStep(StepExecution stepExecution){
            // 执行后进行的操作,主要是更新数据库 log 的状态(成功或者失败)
        }
    }

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值