如何使用不同的参数运行Spring批处理作业?

时间:2017-02-15 15:00:01

标签: spring spring-batch

我正在使用弹簧批与自定义读者和作家。

我有一个控制表 customerId

我需要多次运行相同的步骤,对我控制表中的每个客户执行一次。

customerId应该能够作为参数传递,因为我在阅读器和作者中都需要它。

如何才能最好地实现这一目标?

  @Bean
public Step shipmentFactsStep() {
    return stepBuilderFactory.get("shipmentFactsStep")
            .<Shipmentfacts, Shipmentfacts>chunk(10000)
            .reader(shipmentfactsItemReader())
            .processor(shipmentFactProcessor())
            .writer(shipmentFactsWriter())
            .build();
}

1 个答案:

答案 0 :(得分:0)

实现这一目标的一种方法是Partitioning。如果您希望跟踪哪个customersIds已经完成,这种方法似乎更好,因为每个客户ID都有一个从属步骤。

的步骤

1.首先通过实现org.springframework.batch.core.partition.support.Partitioner接口创建分区器类,并为每个客户ID填充Map<String, ExecutionContext>

由于您按客户ID进行分区,因此方法参数gridSize将不会用于您的案例。

代码看起来像这样,其中allCustomers是您从数据库中准备的列表。

课程 - CustomerPartitioner

Map<String, ExecutionContext> result = new HashMap<>();
int partitionNumber = 0;
 for (String customer: allCustomers) {
        ExecutionContext value = new ExecutionContext();
        value.putString("customerId", customer);
        result.put("Customer Id [" + customer+ "] : THREAD "
            + partitionNumber, value);
        partitionNumber++;
        }

2.根据主步和从步骤修改步骤定义。请参阅在线教程。

示例代码与此类似。

@Bean
    public Step customerPartitionerStep() throws Exception {
    return step.get("customerPartitionerStep")
        .partitioner(shipmentFactsStep())
        .partitioner("shipmentFactsStep", customerPartitioner())
        .gridSize(partitionerGridSize).taskExecutor(taskExecutor())
        .build();
    }

    @Bean
public Step shipmentFactsStep() {
    return stepBuilderFactory.get("shipmentFactsStep")
            .<Shipmentfacts, Shipmentfacts>chunk(10000)
            .reader(shipmentfactsItemReader())
            .processor(shipmentFactProcessor())
            .writer(shipmentFactsWriter())
            .build();
}

@Bean
    public Partitioner customerPartitioner() {
    return new CustomerPartitioner();
    }

@Bean
    public TaskExecutor taskExecutor() {
    SimpleAsyncTaskExecutor simpleTaskExecutor = new SimpleAsyncTaskExecutor();
    simpleTaskExecutor.setConcurrencyLimit(concurrencyLimit);
    return simpleTaskExecutor;
    }

您可以将partitionerGridSize设置为任何值,因为它未在分区程序实现中使用。您可以稍后使用它来根据总数记录而不是仅根据客户ID进行分区。

3.在上面步骤#2的代码中,设置concurrencyLimit=1非常重要..这样一次只能运行一个客户,并且它将为您在步骤#中输入的所有客户运行1。通过设置此值,您可以并行运行任意数量的客户。

4。步骤#1步骤中来自分区的customerId可以通过读取,处理器等访问

@Bean
@StepScope
public ItemReader<ReadBean> shipmentfactsItemReader(
        @Value("#{stepExecutionContext[customerId]}" String customerId){
..
}

请注意注释@StepScope ..这对于此值的绑定是必需的。此外,在您的阅读器定义中,您需要通过null这样的举例 - .reader(shipmentfactsItemReader(null))

在Spring Batch元数据中,您将拥有与客户数量相同的步骤以及一个主步骤。所有从属步骤完成后,主步骤将结束。

此处的优点是,如果需要,您可以并行处理许多客户,并且客户的每个从属步骤都将在其自己的单独线程中运行。

希望它有所帮助!!