【问题标题】:How to run Spring Batch Jobs in certain order (Spring Boot)?如何按特定顺序运行 Spring Batch Jobs(Spring Boot)?
【发布时间】:2017-05-12 20:45:30
【问题描述】:

我正在使用 Spring Boot 使用 Spring Batch 进行开发。

我使用 Spring Boot 提供的最小配置并定义了一些作业(根本没有 XML 配置)。但是当我运行应用程序时,

SpringApplication.run(App.class, args);

作业以任意顺序顺序执行。

我在 @Configuration 带注释的类中以这种方式定义作业,其余的由 Spring 完成:

@Bean
public Job requestTickets() {
    return jobBuilderFactory.get(Config.JOB_REQUEST_TICKETS)
            .start(stepRequestTickets())
            .build();
}

如何指示框架按特定顺序运行作业?

编辑:这个警告能给出提示吗? (也许没什么)

2016-12-29 17:45:33.320  WARN 3528 --- [main] o.s.b.c.c.a.DefaultBatchConfigurer: No datasource was provided...using a Map based JobRepository

【问题讨论】:

  • 所以你有一份工作有多个步骤或多个工作?好像,你只有一份工作。当您说 jobs 时,您是指 steps 吗?显示stepRequestTickets() 的代码。
  • 我有多个工作。我想按固定顺序依次运行作业,但找不到订购作业的方法。这只是我如何定义 Job 的一个 sn-p。

标签: java spring spring-boot spring-batch


【解决方案1】:

1.您首先通过在 application.properties

中指定 spring.batch.job.enabled=false 来禁用自动作业启动

2.在你的主类中,做 - ApplicationContext ctx = SpringApplication.run(SpringBatchMain.class, args); 假设你的主类被命名为 - SpringBatchMain.java。

这将在不启动任何作业的情况下初始化上下文。

3.一旦上下文被初始化,你可以做 - JobLauncher jobLauncher = (JobLauncher) ctx.getBean("jobLauncher"); 或在主类中为这个 JobLauncher bean 做 Autowired 并通过调用 jobLauncher.run(job, jobParameters) 以特定顺序依次启动特定作业。

您可以从第 2 步初始化的上下文中获取特定的 job 实例。

您始终可以使用任何有序集合将您的作业放在那里,并通过迭代该集合来启动作业。

4. 只要您的 JobLauncher 配置为同步,即主线程等待 jobLauncher.run() 调用完成,并且这是 jobLauncher 的默认行为,上述技术就可以工作。

如果您已将 jobLauncher 定义为使用 AsyncTaskExecutor,则作业将并行启动,并且不会保持顺序排序。

希望对你有帮助!!

编辑:

我正在试验 Stephane Nicoll 指出的 @Order 注释,它似乎只有助于创建有序的作业集合,并且您可以按该顺序迭代和启动作业。

这个下面的组件给了我指定顺序的工作,

@Component
public class MyJobs {
    @Autowired
    private List<Job> jobs;

    public List<Job> getJobs() {
        return jobs;
    }
}

我可以做到,MyJobs myJobs = (MyJobs) ctx.getBean("myJobs"); 在主类中提供 bean 已定义,

@Bean
    public MyJobs myJobs() {
        return new MyJobs();
    }

我可以遍历myJobs 并按照@Order 注释指定的顺序启动作业。

【讨论】:

  • 成功了!但是一个额外的问题:您将@Beancode 放在哪里?如果我将它放在main 方法中,它工作正常。但是如果我把它放在 @Component 里面,我会得到一个 Spring 错误:BeanDefinitionStoreException: Invalid bean definition with name 'myJobs' defined in class path resource [.../MyJobs.class]: factory-bean reference points back to the same bean definition
  • 我发现@Bean 的定义是不必要的。我猜@Component 已经创建了所需的 bean。
  • 我的意思是,如果您的工作太多且难以管理,则需要使用 Order。对于一两个作业,您可以简单地手动启动作业,而无需使用订单注释。
  • 我使用@Order 管理它并遍历作业列表以运行作业。但我不需要声明@Bean myJobs() 代码。我可以在没有声明 @Bean 的情况下制作 ctx.getBean(MyJobs.class).getJobs(),只需使用 @Component 部分。谢谢让它工作:)
【解决方案2】:

订购它们。

@Bean
@Order(42)
public Job requestTickets() {
    return jobBuilderFactory.get(Config.JOB_REQUEST_TICKETS)
            .start(stepRequestTickets())
            .build();
}

有关详细信息,请参阅javadoc of @Order

【讨论】:

  • @Order 没有成功。我完全按照您的建议将注释插入了 @Order(1)@Order(2)@Order(3) 到我的 3 个作业中,但它们的执行方式与以前一样。
  • 那么您没有使用作业启动器。或者您使用的是非常旧的 Spring Boot 版本。
  • @StephaneNic​​oll:那你是什么意思,那么你没有使用作业启动器jobLauncher.run(job, jobParameters) 运行特定的作业,所以它就像手动订购一样。我也测试了@Order,但它没有按照您的回答中描述的那样工作。我正在使用 Spring Boot 1.4.0。不知道 OP 有没有更新?
  • 对我来说,无论 Job bean 首先在 @Configuration 类中定义,无论 Order 是否指定,都会首先执行,
【解决方案3】:

这是解决方案的说明。

这太奇怪了,看起来我们正在破解进程。

spring.batch.job.enabled=false

@SpringBootApplication
@EnableBatchProcessing
public class MyApplication {

    public static void main(String[] args)
            throws JobParametersInvalidException, JobExecutionAlreadyRunningException, JobRestartException, JobInstanceAlreadyCompleteException {

        ConfigurableApplicationContext ctx = SpringApplication.run(MyApplication.class, args);
        JobLauncher jobLauncher = (JobLauncher) ctx.getBean("jobLauncher");
        Job job1= (Job) ctx.getBean("job1");
        Job job2= (Job) ctx.getBean("job2");
        jobLauncher.run(job1,new JobParameters());
        jobLauncher.run(job2,new JobParameters());
    }

}

【讨论】:

    【解决方案4】:

    我没有足够的代表发表评论。但是您是否尝试过按照您想要的顺序手动启动您的工作?

    您需要在 application.properties 中设置 spring.batch.job.enabled=false,以便您的作业不会自动运行。

    然后只需使用启动器按您想要的顺序启动您的作业。

    @RunWith(SpringRunner.class)
    @SpringBootTest(classes = { TestConfiguration.class, TestDataSourceConfiguration.class, TestBatchConfig.class })
    public class JobOrderTest {
    
        @Autowired
        JobLauncher jobLauncher;
    
        @Mock
        Job firstJob;
    
        @Mock
        Job secondJob;
    
        @Mock
        Job thirdJob;
    
        @Mock
        JobParametersValidator jobParametersValidator;
    
        @Test
        public void jobInOrderTest() throws JobExecutionAlreadyRunningException, JobRestartException, JobInstanceAlreadyCompleteException, JobParametersInvalidException {
    
            when(firstJob.getName()).thenReturn(UUID.randomUUID().toString());
            when(secondJob.getName()).thenReturn(UUID.randomUUID().toString());
            when(thirdJob.getName()).thenReturn(UUID.randomUUID().toString());
            when(firstJob.getJobParametersValidator()).thenReturn(jobParametersValidator);
            when(secondJob.getJobParametersValidator()).thenReturn(jobParametersValidator);
            when(thirdJob.getJobParametersValidator()).thenReturn(jobParametersValidator);
    
            jobLauncher.run(firstJob, new JobParameters());
            jobLauncher.run(secondJob, new JobParameters());
            jobLauncher.run(thirdJob, new JobParameters());
        }
    
    }
    

    这是输出

    2016-12-30 09:48:36.457  INFO 144860 --- [cTaskExecutor-1] o.s.b.c.l.support.SimpleJobLauncher      : Job: [firstJob] launched with the following parameters: ...
    2016-12-30 09:48:36.457  INFO 144860 --- [cTaskExecutor-1] o.s.b.c.l.support.SimpleJobLauncher      : Job: [firstJob] completed with the following parameters: ...
    2016-12-30 09:48:36.478  INFO 144860 --- [cTaskExecutor-2] o.s.b.c.l.support.SimpleJobLauncher      : Job: [secondJob] launched with the following parameters: ...
    2016-12-30 09:48:36.478  INFO 144860 --- [cTaskExecutor-2] o.s.b.c.l.support.SimpleJobLauncher      : Job: [secondJob] completed with the following parameters: ...
    2016-12-30 09:48:36.508  INFO 144860 --- [cTaskExecutor-3] o.s.b.c.l.support.SimpleJobLauncher      : Job: [thirdJob] launched with the following parameters: ...
    2016-12-30 09:48:36.508  INFO 144860 --- [cTaskExecutor-3] o.s.b.c.l.support.SimpleJobLauncher      : Job: [thirdJob] completed with the following parameters: ...
    

    【讨论】:

      【解决方案5】:

      如果您的一项工作依赖于第二项工作,依此类推,请执行以下操作。

      @Configuration
      @EnableBatchProcessing
      @Import(DataSourceConfiguration.class)
      public class AppConfig {
      
          @Autowired
          private JobBuilderFactory jobs;
      
          @Autowired
          private StepBuilderFactory steps;
      
          @Bean
          public Job job(@Qualifier("step1") Step step1, @Qualifier("step2") Step step2) {
              return jobs.get("myJob").start(step1).next(step2).build();
          }
      
          @Bean
          protected Step step1(ItemReader<Person> reader, ItemProcessor<Person, Person> processor, ItemWriter<Person> writer) {
              return steps.get("step1")
                  .<Person, Person> chunk(10)
                  .reader(reader)
                  .processor(processor)
                  .writer(writer)
                  .build();
          }
      
          @Bean
          protected Step step2(Tasklet tasklet) {
              return steps.get("step2")
                  .tasklet(tasklet)
                  .build();
          }
      }
      

      【讨论】:

      • 我认为您在谈论订购步骤,但我需要按特定顺序运行 JOBS,因为 Job_n 取决于 Job_n-1
      猜你喜欢
      • 2020-09-24
      • 2019-10-14
      • 2020-09-24
      • 2021-09-01
      • 2018-07-10
      • 2021-05-12
      • 1970-01-01
      • 2015-08-19
      • 2017-04-20
      相关资源
      最近更新 更多