我想使用Spring Batch(v3.0.9)重新启动功能,以便JobInstance
重新启动时,该处理步骤将从最后一个失败的块点开始读取。只要不对@StepScope
bean方法使用myBatisPagingItemReader
批注,重新启动就可以正常工作。
我正在使用@StepScope
,以便可以进行后期绑定,以在我的JobParameters
bean方法myBatisPagingItemReader
中得到@Value("#{jobParameters['run-date']}"))
如果我在@StepScope
bean方法上使用myBatisPagingItemReader()
批注,则重新启动将无法正常进行,因为它会创建新实例(scope = step,name = scopedTarget.myBatisPagingItemReader)。
如果我使用stepscope,myBatisPagingItemReader是否可以从上次失败开始设置read.count以便重新启动工作?
我已经在下面的示例中解释了这个问题。
@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条记录,并且我将块大小(commit-interval)设置为3。
作业实例-01-作业参数-01/02/2019。
块1:
-流程记录1
-流程记录2
-流程记录3
writer-写全部3条记录
chunk-1提交成功
chunk-2:
流程记录4
流程记录5-引发和异常
作业完成并设置为“失败”状态
现在,使用相同的作业参数重新启动作业。
作业实例-01-作业参数-01/02/2019。
块1:
流程记录1
流程记录2
流程记录3
writer-写全部3条记录
chunk-1提交成功
chunk-2:
流程记录4
流程记录5-引发和异常
作业完成并设置为“失败”状态
@StepScope
bean方法上的myBatisPagingItemReader()
注释创建一个新实例,请参见下面的日志消息。
在scope = step,name = scopedTarget.myBatisPagingItemReader
中创建对象
在scope = step,name = scopedTarget.myBatisPagingItemReader
中注册的销毁回调
由于它是新实例,因此它从头开始而不是从chunk-2开始。
如果我不使用@Stepscope
,则从重新启动的作业步骤设置的块2重新启动-MyBatisPagingItemReader.read.count = 3。
答案 0 :(得分:1)
这里的问题是,您返回的是ItemReader
而不是完全合格的类(MyBatisPagingItemReader
)或至少是ItemStreamReader
。当您使用Spring Batch的step作用域时,我们创建一个代理以允许后期初始化。代理基于方法的返回类型(在您的情况下为ItemReader
)。您遇到的问题是,因为代理是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尽可能提供帮助。