当前位置: 首页 > 知识库问答 >
问题:

使用@stepscope时Spring批重新启动功能不工作

唐经国
2023-03-14

我想使用Spring批处理(V3.0.9)重新启动功能,以便在jobinstance重新启动时,流程步骤从上一个失败的块点向前读取。只要不对myBatisPagingItemReaderbean方法使用@stepscope批注,我的重新启动就可以正常工作。
我使用了@stepscope以便在我的myBatisPagingItemReaderbean方法@value(“#{jobParameters['run-date']}”)
如果对myBatisPagingItemReader()bean方法使用@stepscope

我用下面的例子解释了这个问题。

@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
写入器-写入所有3条记录
块-1提交成功

块2:
进程记录-4
进程记录-5-抛出和异常
作业完成并设置为“失败”状态

现在使用相同的作业参数再次重新启动作业。
作业实例-01-作业参数-01/02/2019。
chunk-1:
进程记录-1
进程记录-2
进程记录-3
writer-写入所有3条记录
chunk-1提交成功

块2:
进程记录-4
进程记录-5-抛出和异常
作业完成并设置为“失败”状态

MyBatiSpagingItemReader()bean方法上的@stepscope注释创建了一个新实例,请参阅下面的日志消息。
在scope=step,name=ScopedTarget中创建对象。MyBatiSpagingItemReader
在scope=step,name=ScopedTarget中注册了销毁回调。MyBatiSpagingItemReader
因为是新实例,所以它从start开始进程,而不是从Chunk-2开始。

如果不使用@stepscope,它将从块-2重新启动,因为重新启动的作业步骤集-mybatispagingitemreader.read.count=3。

共有1个答案

陶博涉
2023-03-14

这里的问题是,您返回的是ItemReader而不是完全限定类(MyBatispagingItemReader)或至少是ItemStreamReader。当您使用Spring Batch的step范围时,我们会创建一个代理来允许后期初始化。代理基于方法的返回类型(在您的示例中为itemreader)。您遇到的问题是,因为代理是itemreader,所以Spring Batch不知道您的bean也实现了itemstream,而正是该接口启用了可重启性。默认情况下,Spring批处理将自动为您注册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尽可能地提供帮助。

 类似资料:
  • 我是C编程的初学者,如果我能得到一些关于如何重新启动程序的提示,我将不胜感激?我目前正在开发一个猜测游戏,用户有10次尝试猜测随机提供的秘密号码。我希望该程序能够从一开始就为用户提供新一轮游戏(尝试次数1猜测次数:),这意味着重新运行该程序。 以下是节目:

  • 我有一个活动,我们称之为FirstActivity.java,它有一个带有通过片段实例化的导航抽屉的actionBar。在这个片段NavigationDrawerFragment.java中,为了实例化ActionBar,我将方法onCreateOptionsMenu(菜单菜单,MenuInflater inflater)、onOptionsItemSelected(MenuItem项)和onPr

  • 我使用的是Spring批处理版本2.2.4.Release,我试图用有状态的ItemReader、ItemProcessor和ItemWriter bean编写一个简单的示例。 在我的集成测试中,我在一个内部静态java配置类中声明bean,如下所示: 这个测试通过了。 但是,一旦我将StatefulItemReader定义为step范围的bean(这对于有状态的读取器更好),“Before st

  • 我正在尝试重新开始使用Spring Boot开发工具。我一直遵循此处提供的说明:https://docs.spring.io/spring-boot/docs/current/reference/html/using-boot-devtools.html 我正在使用gradle,并将其包含在我的build.gradle文件中: 我创建jar文件并运行jar文件: 我能够通过Intellij连接到正

  • 我有一个spring批处理作业,从CSV文件读取并写入数据库。我想让它重新启动。例如,如果在读取文件或写入db时出现异常,导致作业失败,则应从失败的同一点/块重新开始,而不是从头开始读取整个文件。 我正在从一个endpoint触发作业启动器,并在我的控制器中配置了它。 目前,我正在通过控制器将参数(这是一个唯一的标识符/数字)传递给作业参数,以运行新的作业实例。如果作业失败,我将使用与GET请求中

  • 我在网上看了很多关于< code > spring-boot-dev tools 的文章和问题,但是仍然不明白为什么它对我不起作用。每次运行我的应用程序,我都会得到以下信息: 每当我更改其中一个控制器文件时,什么也没发生。所以我遇到了一篇文章,提到我应该尝试将添加到我的应用程序属性文件中。使用 src 将不起作用,因为它会认为这是一个绝对路径,所以我将其更改为 。完成此操作后,将新endpoint