将数据传递到将来的步骤-Spring Batch

时间:2018-09-11 08:38:36

标签: spring spring-batch batch-processing

我们可以在Spring批处理正式文档中看到“将数据传递到将来的步骤-Spring Batch”是可能的,但是我们大多数人都在为此苦苦挣扎,因为他们在正式文档中提到了两种可能性。 步骤级别和一个工作级别。问题是如何在步骤级别检索数据?

我的解决方案与官方文档中的解决方案相同,但是没有用。因此,我决定执行以下操作:

1-创建用于升级侦听器的bean:

<beans:bean id="promotionListener"
                class="org.springframework.batch.core.listener.ExecutionContextPromotionListener">
        <beans:property name="keys" value="someValues"/>
</beans:bean>

2-在您的步骤中设置侦听器(您要保存数据的步骤)

        <listeners>
            <listener ref="promotionListener"/>
        </listeners>

3-在编写器的同一步骤(保存数据的步骤)中,保存数据。

private StepExecution stepExecution;

    @BeforeStep
    public void saveStepExecution(StepExecution stepExecution) {
        this.stepExecution = stepExecution;

        ExecutionContext executionContext = stepExecution.getExecutionContext();
        Map<String, String> fieldsMap= new HashMap<>();
        executionContext.put("keys", someValues);
    }

@Override
public void write(List<? extends Map<String, String>> items) throws Exception {
    LOGGER.info(items.toString());

    Map<String, String> fieldsMap= new ConcurrentHashMap<>();
    items.forEach(item -> item.forEach(fieldsMap::put));

    ExecutionContext stepContext = this.stepExecution.getExecutionContext();
    stepContext.put("keys", fieldsMap);
}

对于我来说,您可以看到我正在将数据保存在Map(ConcurrentHashMap)中。

4-重要信息:在下一步中,您要检索上一步中保存的数据。按照该顺序,我们必须执行以下操作:

  • 声明将包含我们将检索为的值的对象:

    私人地图栏位地图;

请注意 JobExecution

enter image description here

@BeforeStep
    public void retrieveInterStepData(StepExecution stepExecution) {
        JobExecution jobExecution = stepExecution.getJobExecution();
        Collection<StepExecution> stepExecutions = jobExecution.getStepExecutions();
        for (StepExecution steps : stepExecutions) {
            ExecutionContext executionContext = steps.getExecutionContext();
            if (executionContext.containsKey("keys")) {
                this.nationalityMap = (Map<String, String>) executionContext.get("keys");
            }
        }
    }

就是这样! 您可能想知道为什么我不遵循官方文档中的说明?原因是我在同一工作中与Steps一起工作。他们共享相同的工作执行。现在看看我的调试模式。

如果还有其他建议,请提出建议。

注意:请不要仅从正式文档中复制和粘贴代码,也不提供您自己的答案或实现。

与该问题相关的spring batch文档的链接如下 enter link description here

1 个答案:

答案 0 :(得分:1)

您在混淆将要从步骤执行上下文提升到作业执行上下文的键与数据本身。这种混乱来自两个地方:

  • <beans:property name="keys" value="someValues"/>someValues应该是someKeys
  • executionContext.put("keys", someValues);中调用@BeforeStep是不正确的

让我更清楚一点。想象一下您有两个步骤的工作:

  • 第1步:在步骤执行上下文中读取/写入一些项目并写入项目计数
  • 第2步:需要访问项目计数并将其打印到控制台。

在这种情况下,您可以使用提升侦听器将键“ count”从步骤1的步骤执行上下文提升到作业执行上下文,以便步骤2可以访问它。这是一个示例:

import java.util.Arrays;
import java.util.List;

import org.springframework.batch.core.Job;
import org.springframework.batch.core.JobParameters;
import org.springframework.batch.core.Step;
import org.springframework.batch.core.StepExecution;
import org.springframework.batch.core.annotation.BeforeStep;
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.listener.ExecutionContextPromotionListener;
import org.springframework.batch.item.ExecutionContext;
import org.springframework.batch.item.ItemReader;
import org.springframework.batch.item.ItemWriter;
import org.springframework.batch.item.support.ListItemReader;
import org.springframework.batch.repeat.RepeatStatus;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
@EnableBatchProcessing
public class MyJob {

    @Autowired
    private JobBuilderFactory jobs;

    @Autowired
    private StepBuilderFactory steps;

    @Bean
    public ItemReader<Integer> itemReader() {
        return new ListItemReader<>(Arrays.asList(1, 2, 3, 4));
    }

    @Bean
    public ItemWriter<Integer> itemWriter() {
        return new ItemWriter<Integer>() {

            private StepExecution stepExecution;

            @Override
            public void write(List<? extends Integer> items) {
                for (Integer item : items) {
                    System.out.println("item = " + item);
                }
                ExecutionContext stepContext = this.stepExecution.getExecutionContext();
                int count = stepContext.containsKey("count") ? stepContext.getInt("count") : 0;
                stepContext.put("count", count + items.size());
            }

            @BeforeStep
            public void saveStepExecution(StepExecution stepExecution) {
                this.stepExecution = stepExecution;
            }
        };
    }

    @Bean
    public Step step1() {
        return steps.get("step1")
                .<Integer, Integer>chunk(2)
                .reader(itemReader())
                .writer(itemWriter())
                .listener(promotionListener())
                .build();
    }

    @Bean
    public Step step2() {
        return steps.get("step2")
                .tasklet((contribution, chunkContext) -> {
                    // retrieve the key from the job execution context
                    Integer count = (Integer) chunkContext.getStepContext().getJobExecutionContext().get("count");
                    System.out.println("In step 2: step 1 wrote " + count + " items");
                    return RepeatStatus.FINISHED;
                })
                .build();
    }

    @Bean
    public ExecutionContextPromotionListener promotionListener() {
        ExecutionContextPromotionListener listener = new ExecutionContextPromotionListener();
        listener.setKeys(new String[] {"count"});
        return listener;
    }

    @Bean
    public Job job() {
        return jobs.get("job")
                .start(step1())
                .next(step2())
                .build();
    }

    public static void main(String[] args) throws Exception {
        ApplicationContext context = new AnnotationConfigApplicationContext(MyJob.class);
        JobLauncher jobLauncher = context.getBean(JobLauncher.class);
        Job job = context.getBean(Job.class);
        jobLauncher.run(job, new JobParameters());
    }

}

此打印:

item = 1
item = 2
item = 3
item = 4
In step 2: step 1 wrote 4 items

希望这会有所帮助。