Spring 作业再次运行时 reader 不会 "re-read"

Spring batch reader doesn't "re-read" when job runs again

我正在使用 Spring Batch 来收集有关本地磁盘上文件的元数据。第一次作业 运行s 一切都按预期工作,但是第二次执行作业时我希望它重新收集该信息。目前作业重新启动并以 COMPLETE 结束,没有任何处理。

使用简单的 reader

    @Bean(name = "directoryScannerReader")
    public ItemReader<MediaFileDto> reader() {

        final String directory = "/some/path";

        try {
            return new IteratorItemReader<>(scanService.scanMedia(directory));
        } catch (IOException e) {
            throw new RuntimeException("Stop everything. Unable to read from directory");
        }

    }

scanService 只是 returns 一组文件供进一步处理

我每分钟都会按计划启动它

    @Scheduled(fixedDelayString = "${batch.delay}")
    public void schedule() throws JobExecutionException {
        simpleJobLauncher.run(job, new JobParametersBuilder().addDate("date", new Date()).toJobParameters());
    }

如果我重新启动应用程序,第一个 运行 将按预期扫描文件。

启动作业时需要传入什么吗?还是有更合适的 reader 可以使用?

问题在于,一旦您的应用程序上下文被加载,ItemReader bean 在您的应用程序的整个生命周期内都是相同的。因此,一旦在应用程序启动期间初始化它,相同的 bean 实例将用于后续调用(因此您的服务不会再次调用以扫描目录)。

解决这个问题的方法是使 reader 步骤限定范围并将目录作为参数传递,例如:

@Bean(name = "directoryScannerReader")
@StepScope
public ItemReader<MediaFileDto> reader(@Value("#{jobParameters['directory']}") String directory) {
    try {
        return new IteratorItemReader<>(scanService.scanMedia(directory));
    } catch (IOException e) {
        throw new RuntimeException("Stop everything. Unable to read from directory");
    }

}

并在启动时将目录作为作业参数传递:

@Scheduled(fixedDelayString = "${batch.delay}")
public void schedule() throws JobExecutionException {
    JobParameters jobParameters = new JobParametersBuilder()
            .addDate("date", new Date())
            .addString("directory", "/some/path")
            .toJobParameters();
    simpleJobLauncher.run(job, jobParameters);
}

使用这种方法,您将为每个 运行 都有一个新的作业实例,其中每次都会重新加载范围为 reader 的步骤。

此外,将目录作为作业参数传递允许您在需要时重复使用相同的作业来扫描不同的目录,如果路径在 reader 的定义中被硬编码,则情况并非如此。