如何使用分区和ItemReader获取文件对象?

时间:2019-02-21 12:03:04

标签: spring-batch

我认为这应该是一个很常规的用例,但是我对spring-batch还是很陌生,并被一些概念所迷惑。

我希望有一个从目录中读取文件的批处理过程(将它们作为File对象获取)。还应该对其进行分区可重启

搜索主要生成FlatFileItemReader的示例,我认为不是我所需要的(我不想读取它们,只需将它们作为File发送给处理器)即可。

此刻,我的分区器和读取器看起来像这样。

@Bean("partitioner")
@StepScope
public Partitioner partitioner() {
    MultiResourcePartitioner partitioner = new MultiResourcePartitioner();
    ResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
    Resource[] resources = null;
    try {
        resources = resolver.getResources("classpath*:/*.json");
    } catch (IOException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }
    partitioner.setResources(resources);
    partitioner.partition(10);
    return partitioner;
}

@Bean
@StepScope
@Qualifier("fileItemReader")
@DependsOn("partitioner")
public  ItemReader<File> fileItemReader(@Value("#{stepExecutionContext['fileName']}") String fileName){
    log.info("fileName from stepExecutionContext is " + fileName);

        return new ItemReader<File>() {
            //Reader has to return null, when he ended
            boolean fileHasBeenRead = false;

            @Override
            public File read() throws CustomRetryableException, FileNotFoundException {

                if (fileHasBeenRead == true){
                    log.info("has been read already");
                    return null;
                }
                else {
                    fileHasBeenRead = true;
                    return ResourceUtils.getFile(fileName);
            }
        }
    };
}

我觉得这个阅读器实现不是很好,而且似乎也无法重启。

我找到了另一个阅读器示例,但不知道它是否适用于分区FileReader Example

我也偶然发现了MultiResourceItemReader,但不确定是否也可以解决。

使用分区和ItemReader来处理File对象同时又具有可重启性的最佳方法是什么?

1 个答案:

答案 0 :(得分:0)

Spring Batch不提供任何返回ItemReader对象的File实现,因此您正确地需要自己实现。到此为止,让我们看一下Spring Batch如何使其组件可重启。

启用重新启动功能的主要界面是ItemStream界面。该界面有以下三种方法:

public interface ItemStream {

    void open(ExecutionContext executionContext) throws ItemStreamException;

    void update(ExecutionContext executionContext) throws ItemStreamException;

    void close() throws ItemStreamException;
}

open方法用于建立组件的状态并初始化需要该组件的任何组件(打开文件/等)。这也是在重新启动作业时恢复组件状态的位置。从ExecutionContext检索状态,无非就是先前执行中保存的键/值对映射。

通过update方法可以使组件有机会定期保存其当前状态。诸如读取的记录数之类的内容将存储在ExecutionContext中,稍后将其保存到作业存储库中,以供以后在重新启动时进行引用(通过上面讨论的open方法)。

最后,close方法用于释放任何不需要的资源并执行任何最终清理(关闭文件和数据库连接等)。

当我们考虑先前的方法时,可重启组件将实现ItemStream接口,以便update方法将保存重启到ExecutionContext和打开方法将查找该状态,如果存在,则将其还原(如果没有以前的状态,则不是重启)。

考虑到所有这些,我们现在可以看看您创建ItemReader实现的特定用例,该实现允许返回File对象并且可以重新启动。在这种情况下,您实际上有两件事要确定:

  1. 如何使数据集静态-在大多数使用Spring Batch的重启情况下,假定数据集在两次运行之间均未更改。在您的情况下,期望的是文件列表在执行之间没有变化。如果有的话,使其可重新启动的能力将变得更加复杂。处理此问题的一种好方法是,对于每个作业实例,将要处理的文件以某种方式(重命名)进行标记或移到“处理”目录中,该目录在执行之间不会更改。
  2. 要存储的状态-将数据集设为静态后,Spring Batch可以帮助您使其重新启动。我将扩展AbstractItemCountingItemStreamItemReader。父类将自动计算已返回的项目数,并将它们存储在ExecutionContext中。这意味着,当您遍历Resource对象的数组时,AbstractItemCountingItemStreamItemReader将跟踪您所在的索引。因此,在您的open方法中,您可以获取资源数组并对其进行排序。从那里开始,您将拥有一个一致的数据集,您所需要的就是索引,以识别已阅读的项目和未阅读的项目。

祝你好运,希望对你有帮助!