使用@StepScope时,Spring Batch重新启动功能不起作用

时间:2019-02-04 09:50:03

标签: spring-batch

我想使用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。

1 个答案:

答案 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尽可能提供帮助。