SpringBatch(三):作业与步骤上下文

2023年 9月 14日 120.7k 0

专栏上文章:

Spring Batch(一):入门案例与详细案例分析 - 掘金 (juejin.cn)

SpringBatch(二):作业对象 Job - 掘金 (juejin.cn)

SpringBatch(三):作业与步骤上下文

语文中有个词叫上下文,比如:联系上下文解读一下作者所有表达意思。从这看上下文有环境,语境,氛围的意思。类比到编程,业内也喜欢使用Context表示上下文。比如Spring容器: SpringApplicationContext 。有上下文这个铺垫之后,我们来看下Spring Batch的上下文。

Spring Batch 有2个比较重要的上下文:

  • JobContext

    JobContext 绑定 JobExecution 执行对象为Job作业执行提供执行环境(上下文)。

    作用:维护JobExecution 对象,实现作业收尾工作,与处理各种作业回调逻辑

  • StepContext

    StepContext 绑定 StepExecution 执行对象为Step步骤执行提供执行环境(上下文)。

    作用:维护StepExecution 对象,实现步骤收尾工作,与处理各种步骤回调逻辑

1. 执行上下文

除了上面讲的JobContext 作业上下文, StepContext 步骤上线下文外,还有Spring Batch还维护另外一个上下文:ExecutionContext 执行上下文,作用是:数据共享

Spring Batch 中 ExecutionContext 分2大类

  • Job ExecutionContext

    作用域:一次作业运行,所有Step步骤间数据共享。

  • Step ExecutionContext:

    作用域:一次步骤运行,单个Step步骤间(ItemReader/ItemProcessor/ItemWrite组件间)数据共享。

image.png

2. 作业与步骤执行链

image.png

3. 作业与步骤引用链

  • 作业线

    Job---JobInstance---JobContext---JobExecution--ExecutionContext

  • 步骤线

    Step--StepContext --StepExecution--ExecutionContext

4. 作业上下文API

JobContext context = JobSynchronizationManager.getContext();
JobExecution jobExecution = context.getJobExecution();
Map jobParameters = context.getJobParameters();
Map jobExecutionContext = context.getJobExecutionContext();

5. 步骤上下文API

ChunkContext chunkContext = xxx;
StepContext stepContext = chunkContext.getStepContext();
StepExecution stepExecution = stepContext.getStepExecution();
Map stepExecutionContext = stepContext.getStepExecutionContext();
Map jobExecutionContext = stepContext.getJobExecutionContext();

6. 执行上下文API

ChunkContext chunkContext = xxx;
//步骤
StepContext stepContext = chunkContext.getStepContext();
StepExecution stepExecution = stepContext.getStepExecution();
ExecutionContext executionContext = stepExecution.getExecutionContext();
executionContext.put("key", "value");
//-------------------------------------------------------------------------
//作业
JobExecution jobExecution = stepExecution.getJobExecution();
ExecutionContext executionContext = jobExecution.getExecutionContext();
executionContext.put("key", "value");
​

7. 综合案例

需求:观察作业ExecutionContext与 步骤ExecutionContext数据共享

分析:

1>定义step1 与step2 2个步骤

2>在step1中设置数据

作业-ExecutionContext 添加: key-step1-job value-step1-job

步骤-ExecutionContext 添加: key-step1-step value-step1-step

3>在step2中打印观察

作业-ExecutionContext 步骤-ExecutionContext

import com.langfeiyes.batch._04_param_incr.DailyTimestampParamIncrementer;
import org.springframework.batch.core.*;
import org.springframework.batch.core.configuration.annotation.EnableBatchProcessing;
import org.springframework.batch.core.configuration.annotation.JobBuilderFactory;
import org.springframework.batch.core.configuration.annotation.StepBuilderFactory;
import org.springframework.batch.core.launch.JobLauncher;
import org.springframework.batch.core.launch.support.RunIdIncrementer;
import org.springframework.batch.core.listener.JobListenerFactoryBean;
import org.springframework.batch.core.scope.context.ChunkContext;
import org.springframework.batch.core.scope.context.JobContext;
import org.springframework.batch.core.scope.context.JobSynchronizationManager;
import org.springframework.batch.core.scope.context.StepContext;
import org.springframework.batch.core.step.tasklet.Tasklet;
import org.springframework.batch.item.ExecutionContext;
import org.springframework.batch.repeat.RepeatStatus;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
@SpringBootApplication
@EnableBatchProcessing
public class ExecutionContextJob {
    @Autowired
    private JobBuilderFactory jobBuilderFactory;
    @Autowired
    private StepBuilderFactory stepBuilderFactory;
​
    @Bean
    public Tasklet tasklet1(){
        return new Tasklet() {
            @Override
            public RepeatStatus execute(StepContribution contribution, ChunkContext chunkContext) throws Exception {
​
                //步骤
                ExecutionContext stepEC = chunkContext.getStepContext().getStepExecution().getExecutionContext();
                stepEC.put("key-step1-step","value-step1-step");
                System.out.println("------------------1---------------------------");
                //作业
                ExecutionContext jobEC = chunkContext.getStepContext().getStepExecution().getJobExecution().getExecutionContext();
                jobEC.put("key-step1-job","value-step1-job");
​
                return RepeatStatus.FINISHED;
            }
        };
    }
    @Bean
    public Tasklet tasklet2(){
        return new Tasklet() {
            @Override
            public RepeatStatus execute(StepContribution contribution, ChunkContext chunkContext) throws Exception {
​
                //步骤
                ExecutionContext stepEC = chunkContext.getStepContext().getStepExecution().getExecutionContext();
                System.err.println(stepEC.get("key-step1-step"));
                System.out.println("------------------2---------------------------");
                //作业
                ExecutionContext jobEC = chunkContext.getStepContext().getStepExecution().getJobExecution().getExecutionContext();
                System.err.println(jobEC.get("key-step1-job"));
​
​
                return RepeatStatus.FINISHED;
            }
        };
    }
​
    @Bean
    public Step  step1(){
        return  stepBuilderFactory.get("step1")
                .tasklet(tasklet1())
                .build();
    }
    @Bean
    public Step  step2(){
        return  stepBuilderFactory.get("step2")
                .tasklet(tasklet2())
                .build();
    }
​
    @Bean
    public Job job(){
        return jobBuilderFactory.get("execution-context-job")
                .start(step1())
                .next(step2())
                .incrementer(new RunIdIncrementer())
                .build();
    }
    public static void main(String[] args) {
        SpringApplication.run(ExecutionContextJob.class, args);
    }
}
​

运行结果:

image.png

可以看出,在stepContext 设置的参数作用域仅在StepExecution 执行范围有效,而JobContext 设置参数作用与在所有StepExcution 有效,有点局部与全局 的意思。

打开数据库观察表:batch_job_execution_context 跟 batch_step_execution_context 表

JobContext数据保存到:batch_job_execution_context

StepContext数据保存到:batch_step_execution_context

总结:

步骤数据保存在Step ExecutionContext,只能在Step中使用,作业数据保存在Job ExecutionContext,可以在所有Step中共享

相关文章

JavaScript2024新功能:Object.groupBy、正则表达式v标志
PHP trim 函数对多字节字符的使用和限制
新函数 json_validate() 、randomizer 类扩展…20 个PHP 8.3 新特性全面解析
使用HTMX为WordPress增效:如何在不使用复杂框架的情况下增强平台功能
为React 19做准备:WordPress 6.6用户指南
如何删除WordPress中的所有评论

发布评论