java 如何按特定顺序运行 Spring Batch 作业(Spring Boot)?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/41364220/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to run Spring Batch Jobs in certain order (Spring Boot)?
提问by Gerard Bosch
I'm developing with Spring Batch using Spring Boot.
我正在使用 Spring Boot 使用 Spring Batch 进行开发。
I'm with the minimal configuration provided by Spring Boot and defined some Jobs (no XML configuration at all). But when I run the application,
我使用 Spring Boot 提供的最小配置并定义了一些作业(根本没有 XML 配置)。但是当我运行应用程序时,
SpringApplication.run(App.class, args);
the jobs are sequentially executed in some arbitrary order.
作业以某种任意顺序依次执行。
I'm defining the jobs this way in @Configuration
annotated classes, Spring do the rest:
我在带@Configuration
注释的类中以这种方式定义工作,Spring 完成剩下的工作:
@Bean
public Job requestTickets() {
return jobBuilderFactory.get(Config.JOB_REQUEST_TICKETS)
.start(stepRequestTickets())
.build();
}
How can I instruct the framework to run the jobs in a certain order?
如何指示框架按特定顺序运行作业?
EDIT: Could this warning give a hint? (Maybe has nothing to be)
编辑:此警告可以提供提示吗?(也许没什么可说的)
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
回答by Sabir Khan
1.You first disable automatic job start by specifying spring.batch.job.enabled=false
in application.properties
1.您首先通过spring.batch.job.enabled=false
在application.properties 中指定来禁用自动作业启动
2.In your main class, do - ApplicationContext ctx = SpringApplication.run(SpringBatchMain.class, args);
assuming your main class is named - SpringBatchMain.java.
2.在你的主类中,做 -ApplicationContext ctx = SpringApplication.run(SpringBatchMain.class, args);
假设你的主类被命名为 - SpringBatchMain.java。
This will initialize context without starting any jobs.
这将在不启动任何作业的情况下初始化上下文。
3.Once context is initialized, either you can do - JobLauncher jobLauncher = (JobLauncher) ctx.getBean("jobLauncher");
or do Autowired
for this JobLauncher bean in main class and launch specific jobs sequentially in specific sequential order by invoking , jobLauncher.run(job, jobParameters)
.
3.一旦上下文被初始化,您可以在主类中为这个 JobLauncher bean做 -JobLauncher jobLauncher = (JobLauncher) ctx.getBean("jobLauncher");
或做 Autowired
,并通过调用 , 以特定的顺序顺序启动特定的作业jobLauncher.run(job, jobParameters)
。
You can get specific job
instances from context initialized at step # 2.
您可以job
从第 2 步初始化的上下文中获取特定实例。
You can always use any ordered collection to put your jobs there and launch jobs by iterating over that collection.
您始终可以使用任何有序集合将您的作业放在那里,并通过迭代该集合来启动作业。
4.This above technique works as long as your JobLauncher is configured to be synchronous i.e. main thread waits for jobLauncher.run()
call to complete and that is default behavior of jobLauncher.
4.只要您的 JobLauncher 配置为同步,即主线程等待jobLauncher.run()
调用完成,上述技术就可以工作,这是 jobLauncher 的默认行为。
If you have defined your jobLauncher to use AsyncTaskExecutor then jobs will be started in parallel and sequential ordering will not be maintained.
如果您已将 jobLauncher 定义为使用 AsyncTaskExecutor,则作业将并行启动,并且不会保持顺序。
Hope it helps !!
希望能帮助到你 !!
EDIT:
编辑:
I was experimenting with @Order
annotation as pointed by Stephane Nicoll and it seems to help only in creating an Ordered collection of jobs and that you can iterate and launch jobs in that order.
我正在试验@Order
Stephane Nicoll 指出的注释,它似乎只有助于创建有序的作业集合,并且您可以按该顺序迭代和启动作业。
This below component gives me jobs in Order specified ,
下面的组件按指定的顺序为我提供了工作,
@Component
public class MyJobs {
@Autowired
private List<Job> jobs;
public List<Job> getJobs() {
return jobs;
}
}
and I can do , MyJobs myJobs = (MyJobs) ctx.getBean("myJobs");
in main class provided bean is defined,
我可以做到,MyJobs myJobs = (MyJobs) ctx.getBean("myJobs");
在主类中定义了 bean,
@Bean
public MyJobs myJobs() {
return new MyJobs();
}
I can iterate over myJobs
and launch jobs in that order as specified by @Order annotation.
我可以myJobs
按照@Order 注释指定的顺序迭代并启动作业。
回答by Stephane Nicoll
Order them.
订购它们。
@Bean
@Order(42)
public Job requestTickets() {
return jobBuilderFactory.get(Config.JOB_REQUEST_TICKETS)
.start(stepRequestTickets())
.build();
}
See the javadoc of @Order
for more details.
有关更多详细信息,请参阅的javadoc@Order
。
回答by loonis
Here is an illustration of the solution.
这是解决方案的说明。
This is so weird, it looks like we're hacking the process.
这太奇怪了,看起来我们正在破解这个过程。
spring.batch.job.enabled=false
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());
}
}
回答by William Lee
I don't have enough rep to comment. But have you tried just to manually launch your jobs in the order you want?
我没有足够的代表来评论。但是您是否尝试过按照您想要的顺序手动启动您的作业?
You need to set spring.batch.job.enabled=falsein your application.properties, so that your jobs are not run automatically.
您需要在 application.properties 中设置spring.batch.job.enabled=false,以便您的作业不会自动运行。
Then just use a launcher to launch your jobs in the order you want.
然后只需使用启动器按您想要的顺序启动您的作业。
@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());
}
}
Here is the output
这是输出
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: ...
回答by Chandu
if your one job is dependent on the second and so on, then do something like this.
如果你的一份工作依赖于第二份等等,那么做这样的事情。
@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();
}
}