从tasklet存储JobExecutionContext并在另一个tasklet中访问

Dea*_*mer 22 spring-batch

我有一个要求,其中一个tasklet,存储在arraylist目录中的所有文件.列表的大小存储在作业执行上下文中.稍后,在另一个步骤中从另一个tasklet访问此计数.怎么做到这一点.我试图存储在jobexecution上下文中,在运行时抛出不可修改的集合异常,

public RepeatStatus execute(StepContribution arg0, ChunkContext arg1)
throws Exception {
    StepContext stepContext = arg1.getStepContext();
    StepExecution stepExecution = stepContext.getStepExecution();
    JobExecution jobExecution = stepExecution.getJobExecution();
    ExecutionContext jobContext = jobExecution.getExecutionContext();
     jobContext.put("FILE_COUNT",150000);
Run Code Online (Sandbox Code Playgroud)

还将stepexection引用存储在beforestep注释中.但仍然不可能.请让我知道,如何在两个tasklet之间共享数据.

Mic*_*low 55

你有至少4种可能性:

  1. 使用ExecutionPromotionListener 将数据传递给将来的步骤
  2. 使用(spring)bean来保存步骤间数据,例如ConcurrentHashMap
    • 无需进一步操作,重新启动将无法访问此数据
  3. 访问您的tasklet中的JobExecutionContext,应谨慎使用,这将导致并行步骤的线程问题
  4. 使用新的jobcope(春季批次3推出)

从Tasklet访问JobExecution的代码示例:

  1. 设置一个值

    public class ChangingJobExecutionContextTasklet implements Tasklet {
    
        /** {@inheritDoc} */
        @Override
        public RepeatStatus execute(StepContribution contribution, ChunkContext chunkContext) throws Exception {
            // set variable in JobExecutionContext
            chunkContext
                    .getStepContext()
                    .getStepExecution()
                    .getJobExecution()
                    .getExecutionContext()
                    .put("value", "foo");
    
            // exit the step
            return RepeatStatus.FINISHED;
        }
    
    }
    
    Run Code Online (Sandbox Code Playgroud)
  2. 提取一个值

    public class ReadingJobExecutionContextTasklet implements Tasklet {
    
        private static final Logger LOG = LoggerFactory.getLogger(ChangingJobExecutionContextTasklet.class);
    
        /** {@inheritDoc} */
        @Override
        public RepeatStatus execute(StepContribution contribution, ChunkContext chunkContext) throws Exception {
            // pull variable from JobExecutionContext
            String value = (String) chunkContext
                                        .getStepContext()
                                        .getStepExecution()
                                        .getJobExecution()
                                        .getExecutionContext()
                                        .get("value");
    
            LOG.debug("Found value in JobExecutionContext:" + value);
    
            // exit the step
            return RepeatStatus.FINISHED;
        }
    }
    
    Run Code Online (Sandbox Code Playgroud)

我创建代码示例,在第一解决方案3 我的弹簧分批示例中找到,见模块复杂和封装interstepcommunication

  • 好吧,它应该可以工作,我只是猜他之前使用过 `chunkContext.getStepContext().getJobExecutionContext().put(...)` ,这会抛出不可修改的异常 (2认同)

use*_*920 5

另一种方法是使用StepExecutionListener在步骤执行后调用的方法。您的tasklet可以实现它并共享本地属性。

public class ReadingJobExecutionContextTasklet implements Tasklet, StepExecutionListener {
    private String value;

    @Override
    public ExitStatus afterStep(StepExecution stepExecution) {
        ExecutionContext jobExecutionContext = stepExecution.getJobExecution().getExecutionContext();

        jobExecutionContext.put("key", value);
        //Return null to leave the old value unchanged.
        return null;
    }
}
Run Code Online (Sandbox Code Playgroud)

因此,在此步骤中,您的bean是一个tasklet和一个像下面这样的监听器。您还应该将您的范围配置为“ step”:

    <batch:step id="myStep" next="importFileStep">
        <batch:tasklet>
            <ref bean="myTasklet"/>
            <batch:listeners>
                <batch:listener ref="myTasklet"/>
            </batch:listeners>
        </batch:tasklet>
    </batch:step>

    <bean id="myTasklet" class="ReadingJobExecutionContextTasklet" scope="step">
Run Code Online (Sandbox Code Playgroud)