如何按特定顺序运行Spring Batch Jobs(Spring Boot)?

时间:2016-12-28 14:38:07

标签: java spring spring-boot spring-batch

我使用Spring Boot开发Spring Batch。

我使用Spring Boot提供的最小配置并定义了一些Jobs(根本没有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

5 个答案:

答案 0 :(得分:6)

1.首先通过在 application.properties

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

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

这将初始化上下文而不启动任何作业。

3.初始化上下文后,您可以在主类中为此JobLauncher bean执行 - JobLauncher jobLauncher = (JobLauncher) ctx.getBean("jobLauncher");或执行Autowired,并通过调用{{1}按特定顺序顺序启动特定作业}。

您可以从步骤#2初始化的上下文中获取特定的jobLauncher.run(job, jobParameters)实例。

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

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

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

希望它有所帮助!!

编辑:

我正在尝试使用Stephane Nicoll指出的jobLauncher.run()注释,它似乎只能帮助创建Ordered的作业集合,并且您可以按顺序迭代并启动作业。

以下组件为我指定了订单中的作业,

@Order

我可以做,@Component public class MyJobs { @Autowired private List<Job> jobs; public List<Job> getJobs() { return jobs; } } 在主类中定义了bean,

MyJobs myJobs = (MyJobs) ctx.getBean("myJobs");

我可以迭代@Bean public MyJobs myJobs() { return new MyJobs(); } 并按照@Order注释指定的顺序启动作业。

答案 1 :(得分:2)

订购它们。

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

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

答案 2 :(得分:1)

这里是解决方案的说明。

这太奇怪了,好像我们正在破解该过程。

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());
    }

}

答案 3 :(得分:0)

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

您需要在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: ...

答案 4 :(得分:-1)

如果你的一个工作依赖于第二个工作,那么就做这样的事情。

@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();
    }
}