当配置了modular=true时,作业在SpringBatch中调用了两次



我正在尝试将Spring Batch用于作业。我有两个作业 tempJob 和 tempJob2,采用两种不同的配置。当尝试使用命令行参数(-Dspring.batch.job.names=tempJob)运行临时作业时,SpringBatch尝试运行tempJob两次,并收到以下错误

2018-06-15 11:36:37.956 信息 14436 --- [ 主要] o.s.b.c.l.support.SimpleJobLauncher : Job: [SimpleJob: [名称=临时作业]]使用以下参数完成: [{TimeStamp=06152018 11:36:30}] 和以下状态:[已完成] 2018-06-15 11:36:38.049 信息 14436 --- [ 主要] 条件评估报告日志记录侦听器 :

启动应用程序上下文时出错。显示条件报告 在启用"调试"的情况下重新运行应用程序。2018-06-15 11:36:38.058 错误 14436 --- [主] o.s.boot.Spring应用程序:应用程序
运行失败

java.lang.IllegalStateException: 无法执行 CommandLineRunner 在 org.springframework.boot.SpringApplication.callRunner(SpringApplication.java:800) [spring-boot-2.0.3.RELEASE.jar:2.0.3.RELEASE] at org.springframework.boot.SpringApplication.callRunners(SpringApplication.java:781) [spring-boot-2.0.3.RELEASE.jar:2.0.3.RELEASE] at org.springframework.boot.SpringApplication.run(SpringApplication.java:335) [spring-boot-2.0.3.RELEASE.jar:2.0.3.RELEASE] at org.springframework.boot.SpringApplication.run(SpringApplication.java:1255) [spring-boot-2.0.3.RELEASE.jar:2.0.3.RELEASE] at org.springframework.boot.SpringApplication.run(SpringApplication.java:1243) [spring-boot-2.0.3.RELEASE.jar:2.0.3.RELEASE] at com.example.springbatchdemo.SpringbatchdemoApplication.main(SpringbatchdemoApplication.java:22) [类/:NA]引起: org.springframework.batch.core.repository.JobInstanceAlreadyCompleteException: 作业实例已存在,并且已完成 参数={时间戳=06152018 11:36:30}。 如果要运行此作业 再次更改参数。 在 org.springframework.batch.core.repository.support.SimpleJobRepository.createJobExecution(SimpleJobRepository.java:130) ~[弹簧批处理核心-4.0.1.发布.jar:4.0.1.发布] at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.8.0_60] 在 sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:1.8.0_60] 在 sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:1.8.0_60] at java.lang.reflect.Method.invoke(Method.java:497) ~[na:1.8.0_60] 在 org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:343) ~[spring-aop-5.0.7.RELEASE.jar:5.0.7.RELEASE] at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:197) ~[spring-aop-5.0.7.RELEASE.jar:5.0.7.RELEASE] at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163) ~[spring-aop-5.0.7.RELEASE.jar:5.0.7.RELEASE] at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:294) ~[spring-tx-5.0.7.RELEASE.jar:5.0.7.RELEASE] at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:98) ~[spring-tx-5.0.7.RELEASE.jar:5.0.7.RELEASE] at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:185) ~[spring-aop-5.0.7.RELEASE.jar:5.0.7.RELEASE] at org.springframework.batch.core.repository.support.AbstractJobRepositoryFactoryBean$1.invoke(AbstractJobRepositoryFactoryBean.java:181) ~[弹簧批处理核心-4.0.1.发布.jar:4.0.1.发布] at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:185) ~[spring-aop-5.0.7.RELEASE.jar:5.0.7.RELEASE] at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:212) ~[spring-aop-5.0.7.RELEASE.jar:5.0.7.RELEASE] at com.sun.proxy.$Proxy 48.createJobExecution(未知来源) ~[na:na] at org.springframework.batch.core.launch.support.SimpleJobLauncher.run(SimpleJobLauncher.java:131) ~[弹簧批处理核心-4.0.1.发布.jar:4.0.1.发布] at org.springframework.boot.autoconfigure.batch.JobLauncherCommandLineRunner.execute(JobLauncherCommandLineRunner.java:163) ~[spring-boot-autoconfigure-2.0.3.RELEASE.jar:2.0.3.RELEASE] at org.springframework.boot.autoconfigure.batch.JobLauncherCommandLineRunner.executeRegisterJobs(JobLauncherCommandLineRunner.java:148) ~[spring-boot-autoconfigure-2.0.3.RELEASE.jar:2.0.3.RELEASE] at org.springframework.boot.autoconfigure.batch.JobLauncherCommandLineRunner.launchJobFromProperties(JobLauncherCommandLineRunner.java:135) ~[spring-boot-autoconfigure-2.0.3.RELEASE.jar:2.0.3.RELEASE] atorg.springframework.boot.autoconfigure.batch.JobLauncherCommandLineRunner.run(JobLauncherCommandLineRunner.java:128) ~[spring-boot-autoconfigure-2.0.3.RELEASE.jar:2.0.3.RELEASE] at org.springframework.boot.SpringApplication.callRunner(SpringApplication.java:797) [春季启动-2.0.3.发布.jar:2.0.3.发布] ...5 个常见框架 省略

2018-06-15 11:36:38.060 信息 14436 --- [主要] s.c.a.AnnotationConfigApplicationContext : Closed org.springframework.context.annotation.AnnotationConfigApplicationContext@770c2e6b: 启动日期 [美国东部时间 2018 年 6 月 15 日星期五 11:36:31];上下文层次结构的根 2018-06-15 11:36:38.061 信息 14436 --- [主要] o.s.c.support.默认生命周期处理器:停止 bean in phase -2147482648 2018-06-15 11:36:38.062 信息 14436 --- [ main] ory$ResourceAnnotation应用程序上下文 : 关闭 ResourceAnnotationApplicationContext:com.example.springbatchdemo.config.TempConfig 2018-06-15 11:36:38.063信息 14436 --- [主要] ory$资源注释应用程序上下文:关闭 ResourceAnnotationApplicationContext:com.example.springbatchdemo.config.TempConfig2 2018-06-15 11:36:38.064 信息 14436 --- [主要] o.s.j.e.a.AnnotationMBeanExporter : Unregister JMX exposed 关闭的豆子 2018-06-15 11:36:38.065 信息 14436 --- [
主要] o.s.j.e.a.注释MBean出口商:取消注册 JMX 暴露的豆子 2018-06-15 11:36:38.065 信息 14436 --- [
main] com.zaxxer.hikari.HikariDataSource : HikariPool-1 - 已启动关机...2018-06-15 11:36:38.098 信息 14436 --- [
main] com.zaxxer.hikari.HikariDataSource : HikariPool-1 - 关机完成。

以下是我的春季批处理配置 这是我的主要课程

@SpringBootApplication
@EnableBatchProcessing(modular=true)
public class SpringbatchdemoApplication {
public static void main(String[] args) {
String[] params = addTimestampAsParameter(args);
SpringApplication.run(SpringbatchdemoApplication.class, params);
}
@Bean
public ApplicationContextFactory runTempJob1() {
return new GenericApplicationContextFactory(TempConfig.class);
}
@Bean
public ApplicationContextFactory runTempJob2() {
return new GenericApplicationContextFactory(TempConfig2.class);
}

public static String[] addTimestampAsParameter(final String[] args){
String[] params = null;
if(null != args){
params = new String[args.length+1];
for(int i=0;i<args.length;i++){
params[i]=args[i];
}
}else{
params = new String[1];
}
SimpleDateFormat sdf = new SimpleDateFormat("MMddyyyy hh:mm:ss");
String timeStamp = sdf.format(new Date());
params[params.length-1] = String.format("TimeStamp=%s", timeStamp);
return params;
}
}

以下是我的配置类

@Configuration
public class TempConfig {
@Autowired
JobBuilderFactory jobBuilder;
@Autowired
StepBuilderFactory stepBuilder;
@Bean
public Tasklet sampleTask(){
return new Tasklet() {
@Override
public RepeatStatus execute(StepContribution arg0, ChunkContext arg1) throws Exception {
System.out.println("Executed Temp Step of TempConfig Job -> TempJob");
return RepeatStatus.FINISHED;
}
};
}
@Bean
public Step tempStep(Tasklet sampleTask){
return stepBuilder.get("tempStep").tasklet(sampleTask).build();
}
@Bean
public Job tempJob(){
return jobBuilder.get("tempJob")
.start(tempStep(null))
.build();
}
}

和第二个作业配置

@Configuration
public class TempConfig2 {
@Autowired
JobBuilderFactory jobBuilder;
@Autowired
StepBuilderFactory stepBuilder;
@Bean
public Step tempStep1(){
return stepBuilder.get("tempStep1").tasklet(new Tasklet() {
@Override
public RepeatStatus execute(StepContribution arg0, ChunkContext arg1) throws Exception {
System.out.println("Executed Temp Step of TempConfig2 Job -> TempJob1");
return RepeatStatus.FINISHED;
}
}).build();
}
@Bean
public Job tempJob1(){
return jobBuilder.get("tempJob1")
.start(tempStep1())
.build();
}
}

当我进一步研究时,我发现,在给出-Dspring.batch.job.names时,SpringBatch使用JobLauncherCommandLineRunner.launchJobFromProperties()方法来执行作业。此方法尝试使用 executeLocalJobs(jobParameters) 和 executeRegisterJobs(jobParameters) 执行作业; 在调试时,我发现我的作业正在通过两种方法执行。

是否有任何解决方案可以使用命令行参数(modular=true)仅运行一次作业。如果您需要更多信息,请提供帮助并告知。

正如@akhil-khandelwal所说,从注释中删除(modular=true)@EnableBatchProcessing可以解决这个问题。它为我解决了。