繁体   English   中英

Spring Batch 3.0:StepExecutionListener 用于分区 Step 并将执行上下文值级联到分区作业

[英]Spring Batch 3.0 : StepExecutionListener for a partitioned Step and cascading of execution context values to the partitioned job

给定一个使用分区的Spring 批处理作业:

<job id="reportingJob" xmlns="http://www.springframework.org/schema/batch">
        <batch:listeners>
            <batch:listener ref="reportingJobExecutionListenerr" />
        </batch:listeners>
        <batch:step id="reportingMasterStep">
            <partition step="reportingSlaveStep"
                partitioner="reportingPartitioner">
                <batch:handler grid-size="10" task-executor="taskExecutor" />
            </partition>
        </batch:step>
</job>

reportingSlaveStep定义为:

<step id="reportingSlaveStep" xmlns="http://www.springframework.org/schema/batch">
        <job ref="reportingSlaveJob" />
</step>

reportingSlaveJob定义为:

    <job id="reportingSlaveJob" xmlns="http://www.springframework.org/schema/batch">
        <batch:listeners>
            <batch:listener ref="reportsOutputListener" />
        </batch:listeners>
        <batch:split id="reportsCreationSplit"
            task-executor="taskExecutor">
            <batch:flow>
                <batch:step id="basicReportStep">
                    <tasklet throttle-limit="5" task-executor="taskExecutor">
                        <batch:chunk reader="basicReportReader"
                            writer="basicReportWriter" commit-interval="500" />
                    </tasklet>
                </batch:step>
            </batch:flow>
            <batch:flow>
                <batch:step id="advancedReportStep">
                    <tasklet throttle-limit="5" task-executor="taskExecutor">
                        <batch:chunk reader="advancedReportDataReader" writer="advancedReportWriter"
                            commit-interval="500" />
                    </tasklet>
                </batch:step>
            </batch:flow>
       </batch:split>
     </job>

我现在有两个问题:

  1. 我想为每个分区创建一个新的reportsOutputListener实例。 我可以通过将reportsOutputListener设置为Step范围的 bean 来实现这一点吗?
  2. 我希望能够访问为reportingJob创建的相同jobExecutionContext ,以便在reportingSlaveJob中访问。 我是否需要对此进行任何特殊处理,或者reportingJob是否也使用了reportingSlaveStepSlaveJob中的同一个jobExecutionContext实例?
  3. 编辑:当我运行上述作业时,有时我会收到一个异常,说“该作业的作业执行已经在运行”,有时我会在MapExecutionContextDao.java:130上收到NullPointerException

编辑:另请注意,对于第 2 点, slaveJob无法访问 reportPartitioner 在stepExecutionContext中添加的值(使用 spring 配置 xml 中#{stepExecutionContext['msbfBatchId']} reportingPartitioner )。 stepExecutionContext中针对键的值显示为null

我想为每个分区创建一个新的 reportsOutputListener 实例。 我可以通过将 reportsOutputListener 设置为 Step 范围的 bean 来实现这一点吗?

答案是肯定的。 (如Mahmoud Ben Hassine的评论中所述)

我希望能够访问为reportingJob 创建的相同jobExecutionContext,以便在reportingSlaveJob 中访问。 我是否需要对此进行任何特殊处理,或者reportingSlaveStepSlaveJob 是否也使用了reportingJob 中的同一个jobExecutionContext 实例?

答案是否定的。 我深入研究了Spring 批处理代码,发现JobStep使用JobParametersExtractor将值从stepExecutionContext复制到JobParameters 这意味着reportingSlaveJob可以从JobParameters而不是StepExecutionContext访问这些值。 也就是说,出于某种原因, Srping Batch 3.0中的DefaultJobParametersExtractor实现似乎没有按预期将值复制到jobParameters 我最终编写了以下自定义提取器:

public class CustomJobParametersExtractor implements JobParametersExtractor {

    private Set<String> keys;

    public CustomJobParametersExtractor () {
        this.keys = new HashSet<>();
    }

    @Override
    public JobParameters getJobParameters(Job job, StepExecution stepExecution) {
        JobParametersBuilder builder = new JobParametersBuilder();
        Map<String, JobParameter> jobParameters = stepExecution.getJobParameters().getParameters();
        ExecutionContext stepExecutionContext = stepExecution.getExecutionContext();
        ExecutionContext jobExecutionContext = stepExecution.getJobExecution().getExecutionContext();

        // copy job parameters from parent job to delegate job
        for (String key : jobParameters.keySet()) {
            builder.addParameter(key, jobParameters.get(key));
        }

        // copy job/step context from parent job/step to delegate job
        for (String key : keys) {
            if (jobExecutionContext.containsKey(key)) {
                builder.addString(key, jobExecutionContext.getString(key));
            } else if (stepExecutionContext.containsKey(key)) {
                builder.addString(key, stepExecutionContext.getString(key));
            } else if (jobParameters.containsKey(key)) {
                builder.addString(key, (String) jobParameters.get(key).getValue());
            }
        }
        return builder.toJobParameters();
    }

    public void setKeys(String[] keys) {
        this.keys = new HashSet<>(Arrays.asList(keys));
    }

}

然后我可以在报告从属步骤中使用上述提取器,如下所示:

<step id="reportingSlaveStep" xmlns="http://www.springframework.org/schema/batch">
        <job ref="reportingSlaveJob" job-parameters-extractor="customJobParametersExtractor"/>
</step>

其中customJobParametersExtractorCustomJobParametersExtractor类型的 bean,它将我们要复制的所有键传递给reportingSlaveJobJobParameters

当我运行上述作业时,有时我会收到一个异常说“该作业的作业执行已经在运行”,有时我会在 MapExecutionContextDao.java:130 上收到 NullPointerException

发生这种情况的原因是因为没有我的CustomJobParameterExtractorreportingSlaveJob会以空JobParameters 对于Spring 批处理创建新的作业实例,每次启动reportingSlaveJob的作业参数必须不同。 使用CustomJobParameterExtractor解决了这个问题。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM