spring-batch - 使用 @StepScope 时 Spring Batch 重启功能不起作用
问题描述
我想使用 Spring Batch (v3.0.9) 重新启动功能,以便在JobInstance
重新启动时流程步骤从最后一个失败的块点向前读取。只要我不对我的bean 方法使用@StepScope
注释,我的重启就可以正常工作。
我正在使用,以便我可以进行后期绑定以获取我的bean 方法
如果我在 bean 方法上使用注释,则重新启动不起作用,因为它会创建新实例(范围 = step,name = scopedTarget.myBatisPagingItemReader)。
如果我使用 stepscope,我的 myBatisPagingItemReader 是否可以从上次失败中设置 read.count 以重新启动工作? myBatisPagingItemReader
@StepScope
JobParameters
myBatisPagingItemReader
@Value("#{jobParameters['run-date']}"))
@StepScope
myBatisPagingItemReader()
我已经用下面的例子解释了这个问题。
@Configuration
@EnableBatchProcessing
public class BatchConfig {
@Bean
public Step step1(StepBuilderFactory stepBuilderFactory,
ItemReader<Model> myBatisPagingItemReader,
ItemProcessor<Model, Model> itemProcessor,
ItemWriter<Model> itemWriter) {
return stepBuilderFactory.get("data-load")
.<Model, Model>chunk(10)
.reader(myBatisPagingItemReader)
.processor(itemProcessor)
.writer(itemWriter)
.listener(itemReadListener())
.listener(new JobParameterExecutionContextCopyListener())
.build();
}
@Bean
public Job job(JobBuilderFactory jobBuilderFactory, @Qualifier("step1")
Step step1) {
return jobBuilderFactory.get("load-job")
.incrementer(new RunIdIncrementer())
.start(step1)
.listener(jobExecutionListener())
.build();
}
@Bean
@StepScope
public ItemReader<Model> myBatisPagingItemReader(
SqlSessionFactory sqlSessionFactory,
@Value("#{JobParameters['run-date']}") String runDate)
{
MyBatisPagingItemReader<Model> reader = new
MyBatisPagingItemReader<>();
Map<String, Object> parameterValues = new HashMap<>();
parameterValues.put("runDate", runDate);
reader.setSqlSessionFactory(sqlSessionFactory);
reader.setParameterValues(parameterValues);
reader.setQueryId("query");
return reader;
}
}
@Stepscope
当我使用注释时重新启动示例myBatisPagingItemReader()
,阅读器正在获取 5 条记录,并且我将块大小(提交间隔)设置为 3。
作业实例 - 01 - 作业参数 - 01/02/2019。
chunk-1:
- process record-1
- process record-2
- process record-3
writer - 写入所有 3 条记录
chunk-1 提交成功
块 2:
进程记录 4
进程记录 5 - 抛出和异常
作业完成并设置为“失败”状态
现在,使用相同的作业参数再次重新启动作业。
作业实例 - 01 - 作业参数 - 01/02/2019。
chunk-1:
进程记录 1
进程记录 2
进程记录 3
写入器 - 写入所有 3 条记录
块 1 提交成功
块 2:
进程记录 4
进程记录 5 - 抛出和异常
作业完成并设置为“失败”状态
bean 方法上的@StepScope
注释myBatisPagingItemReader()
创建了一个新实例,请参见下面的日志消息。
在 scope=step, name=scopedTarget.myBatisPagingItemReader 中创建对象 在 scope=step, name=scopedTarget.myBatisPagingItemReader 中
注册销毁回调
因为它是新实例,所以它从 start 开始,而不是从 chunk-2 开始。
如果我不使用@Stepscope
,它将从块 2 重新启动,因为重新启动的作业步骤设置 - MyBatisPagingItemReader.read.count=3。
解决方案
这里的问题是您返回的是一个ItemReader
而不是完全限定的类 ( MyBatisPagingItemReader
),或者至少是ItemStreamReader
. 当您使用 Spring Batch 的 step 范围时,我们会创建一个代理以允许后期初始化。代理基于方法的返回类型(ItemReader
在您的情况下)。您遇到的问题是,因为代理是 of ItemReader
,所以 Spring Batch 不知道您的 bean 也实现ItemStream
了,并且正是该接口启用了可重新启动性。默认情况下,Spring Batch 会自动ItemStream
为您注册所有类型的 bean(您也可以自己显式注册 bean,但通常不需要)。
为了解决您的问题,以下应该有效(注意返回类型的更改):
@Bean
@StepScope
public MyBatisPagingItemReader<Model> myBatisPagingItemReader(
SqlSessionFactory sqlSessionFactory,
@Value("#{JobParameters['run-date']}") String runDate) {
MyBatisPagingItemReader<Model> reader =
new MyBatisPagingItemReader<>();
Map<String, Object> parameterValues = new HashMap<>();
parameterValues.put("runDate", runDate);
reader.setSqlSessionFactory(sqlSessionFactory);
reader.setParameterValues(parameterValues);
reader.setQueryId("query");
return reader;
}
这就是为什么我建议在可能的情况下,在使用@Bean
带注释的方法时,您应该尽可能返回最具体的类型,以让 Spring 尽可能地提供帮助。
推荐阅读
- java - 允许包装运行长时间操作并超时运行的 Java 类/包
- java - 链表反向功能在java中不起作用
- c# - 如何统一制作2D实时策略相机控制器?
- javascript - 如何在 React 中重新排序树对象?
- java - 存储库可以返回 DDD 中的分页集合吗?
- java - Travis 使用提供的范围构建(java websockets)
- php - Laravel:使用更新的迁移将列添加到表中
- javascript - Adobe Acrobat Pro - 从下拉列表中获取显示值?
- python - 使用“多处理”模块并行枚举循环
- python - PySpark:根据另一列的顺序收集数据框列上的collect_set