Reputation: 29
I'm using kotlin, spring boot 3.0.1 and batch . I create two of job/step configuration. but when i build the project, i've saw the below errors. I'm asking a question because it's hard to change the previous batch example to the latest version. Has anyone solved this problem? Strangely enough, if you take one job out on config, it can running it.
errors
Error starting ApplicationContext. To display the condition evaluation report re-run your application with 'debug' enabled.
2023-01-03T13:47:34.101+09:00 ERROR 68470 --- [ main] o.s.boot.SpringApplication : Application run failed
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'jobLauncherApplicationRunner': Invocation of init method failed
at org.springframework.beans.factory.annotation.InitDestroyAnnotationBeanPostProcessor.postProcessBeforeInitialization(InitDestroyAnnotationBeanPostProcessor.java:195) ~[spring-beans-6.0.3.jar:6.0.3]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.applyBeanPostProcessorsBeforeInitialization(AbstractAutowireCapableBeanFactory.java:420) ~[spring-beans-6.0.3.jar:6.0.3]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1743) ~[spring-beans-6.0.3.jar:6.0.3]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:599) ~[spring-beans-6.0.3.jar:6.0.3]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:521) ~[spring-beans-6.0.3.jar:6.0.3]
at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:326) ~[spring-beans-6.0.3.jar:6.0.3]
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234) ~[spring-beans-6.0.3.jar:6.0.3]
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:324) ~[spring-beans-6.0.3.jar:6.0.3]
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:200) ~[spring-beans-6.0.3.jar:6.0.3]
at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:961) ~[spring-beans-6.0.3.jar:6.0.3]
at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:915) ~[spring-context-6.0.3.jar:6.0.3]
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:584) ~[spring-context-6.0.3.jar:6.0.3]
at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:730) ~[spring-boot-3.0.1.jar:3.0.1]
at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:432) ~[spring-boot-3.0.1.jar:3.0.1]
at org.springframework.boot.SpringApplication.run(SpringApplication.java:308) ~[spring-boot-3.0.1.jar:3.0.1]
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1302) ~[spring-boot-3.0.1.jar:3.0.1]
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1291) ~[spring-boot-3.0.1.jar:3.0.1]
at com.linetest.batch.SpringBatchApplicationKt.main(SpringBatchApplication.kt:15) ~[main/:na]
Caused by: java.lang.IllegalArgumentException: Job name must be specified in case of multiple jobs
at org.springframework.boot.autoconfigure.batch.JobLauncherApplicationRunner.validate(JobLauncherApplicationRunner.java:116) ~[spring-boot-autoconfigure-3.0.1.jar:3.0.1]
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:na]
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77) ~[na:na]
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:na]
at java.base/java.lang.reflect.Method.invoke(Method.java:568) ~[na:na]
at org.springframework.beans.factory.annotation.InitDestroyAnnotationBeanPostProcessor$LifecycleElement.invoke(InitDestroyAnnotationBeanPostProcessor.java:424) ~[spring-beans-6.0.3.jar:6.0.3]
at org.springframework.beans.factory.annotation.InitDestroyAnnotationBeanPostProcessor$LifecycleMetadata.invokeInitMethods(InitDestroyAnnotationBeanPostProcessor.java:368) ~[spring-beans-6.0.3.jar:6.0.3]
at org.springframework.beans.factory.annotation.InitDestroyAnnotationBeanPostProcessor.postProcessBeforeInitialization(InitDestroyAnnotationBeanPostProcessor.java:192) ~[spring-beans-6.0.3.jar:6.0.3]
... 17 common frames omitted
config/SingleStepJobConfig.kt
import com.linetest.batch.tasklet.SimpleTasklet
import mu.KotlinLogging
import org.springframework.batch.core.Job
import org.springframework.batch.core.Step
import org.springframework.batch.core.StepContribution
import org.springframework.batch.core.job.builder.JobBuilder
import org.springframework.batch.core.repository.JobRepository
import org.springframework.batch.core.scope.context.ChunkContext
import org.springframework.batch.core.step.builder.StepBuilder
import org.springframework.batch.repeat.RepeatStatus
import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration
import org.springframework.transaction.PlatformTransactionManager
private val log = KotlinLogging.logger {}
@Configuration
class SingleStepJobConfig(
private val transactionManager: PlatformTransactionManager,
private val jobRepository: JobRepository,
) {
@Bean
fun singleStepJob(): Job {
return JobBuilder("singleStepJob", jobRepository)
.start(singleStep())
.build()
}
@Bean
fun singleStep(): Step {
return StepBuilder("singleStep", jobRepository)
.tasklet(myTaskletAsBean(), transactionManager)
.build()
}
@Bean
fun singleStep2(): Step {
return StepBuilder("singleStep2", jobRepository)
.tasklet({
_: StepContribution,
_: ChunkContext ->
log.info { "single step2 tasklet 2 test" }
RepeatStatus.FINISHED
}, transactionManager)
.build()
}
@Bean
fun myTaskletAsBean(): SimpleTasklet {
val simpleTasklet = SimpleTasklet()
simpleTasklet.setValue("Single Step Job Properties Setup!!!<<--")
return simpleTasklet
}
}
config/MultipleStepJobConfig.kt
import com.linetest.batch.tasklet.SimpleTasklet
import mu.KotlinLogging
import org.apache.logging.log4j.util.Strings
import org.springframework.batch.core.Job
import org.springframework.batch.core.Step
import org.springframework.batch.core.StepContribution
import org.springframework.batch.core.configuration.annotation.EnableBatchProcessing
import org.springframework.batch.core.job.builder.JobBuilder
import org.springframework.batch.core.repository.JobRepository
import org.springframework.batch.core.scope.context.ChunkContext
import org.springframework.batch.core.step.builder.StepBuilder
import org.springframework.batch.repeat.RepeatStatus
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.boot.autoconfigure.batch.BatchProperties
import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration
import org.springframework.transaction.PlatformTransactionManager
private val log = KotlinLogging.logger {}
@Configuration
class MultipleStepJobConfig(
private val transactionManager: PlatformTransactionManager,
private val jobRepository: JobRepository,
) {
@Bean
fun multipleStepJob(): Job {
return JobBuilder("multipleStepJob", jobRepository)
.start(startStep())
.next(processStep())
.next(writeStep())
.build()
}
@Bean
fun startStep(): Step {
return StepBuilder("startStep", jobRepository)
.tasklet({
_: StepContribution,
_: ChunkContext ->
log.info { "multiple Step Start" }
RepeatStatus.FINISHED
}, transactionManager)
.build()
}
@Bean
fun processStep(): Step {
return StepBuilder("processStep", jobRepository)
.tasklet({_: StepContribution,
_: ChunkContext ->
log.info { "Execute processStep >>>>" }
RepeatStatus.FINISHED
}, transactionManager)
.build()
}
@Bean
fun writeStep(): Step {
return StepBuilder("writeStep", jobRepository)
.tasklet({_: StepContribution,
_: ChunkContext ->
log.info { "Execute writeStep >>>>" }
RepeatStatus.FINISHED
}, transactionManager)
.build()
}
}
tasklet/SimpleTasklet.kt
import mu.KotlinLogging
import org.springframework.batch.core.StepContribution
import org.springframework.batch.core.configuration.annotation.StepScope
import org.springframework.batch.core.scope.context.ChunkContext
import org.springframework.batch.core.step.tasklet.Tasklet
import org.springframework.batch.repeat.RepeatStatus
import org.springframework.beans.factory.InitializingBean
import org.springframework.stereotype.Component
private val log = KotlinLogging.logger { }
@Component
@StepScope
class SimpleTasklet : Tasklet, InitializingBean {
private var resource: String? = null
@Throws(Exception::class)
override fun execute(
contribution: StepContribution,
chunkContext: ChunkContext
): RepeatStatus? {
log.info { "Execute SimpleTasklet >>>>" }
return RepeatStatus.FINISHED
}
fun setValue(text:String){
this.resource = text
log.info { "$resource"}
}
@Throws(Exception::class)
override fun afterPropertiesSet() {
log.info { "AfterPropertiesSet" }
}
}
SpringBatchApplication.kt
import org.springframework.boot.autoconfigure.SpringBootApplication
import org.springframework.boot.runApplication
@SpringBootApplication
class SpringBatchApplication
fun main(args: Array<String>) {
runApplication<SpringBatchApplication>(*args)
}
Strangely enough, if you take one job out on config, it can running it.
Existing Example can running. ref. https://www.devkuma.com/docs/spring-batch/start/
the result spring boot 2.5.5
2023-01-04 00:05:48.365 INFO 7829 --- [ main] com.linetest.batch.BatchApplicationKt : Starting BatchApplicationKt using Java 17.0.5 on mC02YR40ALVDL with PID 7829 (/Users/ParkJiho/Documents/workspace/kotlin/spring-batch-test-0102/build/classes/kotlin/main started by ParkJiho in /Users/ParkJiho/Documents/workspace/kotlin/spring-batch-test-0102)
2023-01-04 00:05:48.366 INFO 7829 --- [ main] com.linetest.batch.BatchApplicationKt : No active profile set, falling back to default profiles: default
2023-01-04 00:05:49.267 INFO 7829 --- [ main] c.linetest.batch.tasklet.SimpleTasklet : TESTTESTTEST has been set!!!!!!!!!!1
2023-01-04 00:05:49.267 INFO 7829 --- [ main] c.linetest.batch.tasklet.SimpleTasklet : AfterPropertiesSet
2023-01-04 00:05:49.282 INFO 7829 --- [ main] com.zaxxer.hikari.HikariDataSource : HikariPool-1 - Starting...
2023-01-04 00:05:49.433 INFO 7829 --- [ main] com.zaxxer.hikari.HikariDataSource : HikariPool-1 - Start completed.
2023-01-04 00:05:49.538 INFO 7829 --- [ main] o.s.b.c.r.s.JobRepositoryFactoryBean : No database type set, using meta data indicating: H2
2023-01-04 00:05:49.665 INFO 7829 --- [ main] o.s.b.c.l.support.SimpleJobLauncher : No TaskExecutor has been set, defaulting to synchronous executor.
2023-01-04 00:05:49.722 INFO 7829 --- [ main] com.linetest.batch.BatchApplicationKt : Started BatchApplicationKt in 1.659 seconds (JVM running for 2.351)
2023-01-04 00:05:49.723 INFO 7829 --- [ main] o.s.b.a.b.JobLauncherApplicationRunner : Running default command line with: []
2023-01-04 00:05:49.766 INFO 7829 --- [ main] o.s.b.c.l.support.SimpleJobLauncher : Job: [FlowJob: [name=flowStepJob]] launched with the following parameters: [{}]
2023-01-04 00:05:49.799 INFO 7829 --- [ main] o.s.batch.core.job.SimpleStepHandler : Executing step: [flowStartStep]
2023-01-04 00:05:49.806 INFO 7829 --- [ main] c.l.batch.config.FlowStepJobConfig : Flow Start Step!!<------
2023-01-04 00:05:49.811 INFO 7829 --- [ main] o.s.batch.core.step.AbstractStep : Step: [flowStartStep] executed in 12ms
2023-01-04 00:05:49.816 INFO 7829 --- [ main] o.s.batch.core.job.SimpleStepHandler : Executing step: [flowProcessStep]
2023-01-04 00:05:49.818 INFO 7829 --- [ main] c.l.batch.config.FlowStepJobConfig : flowProcessStep
2023-01-04 00:05:49.819 INFO 7829 --- [ main] o.s.batch.core.step.AbstractStep : Step: [flowProcessStep] executed in 3ms
2023-01-04 00:05:49.823 INFO 7829 --- [ main] o.s.batch.core.job.SimpleStepHandler : Executing step: [flowWriteStep]
2023-01-04 00:05:49.825 INFO 7829 --- [ main] c.l.batch.config.FlowStepJobConfig : flowWriteStep
2023-01-04 00:05:49.827 INFO 7829 --- [ main] o.s.batch.core.step.AbstractStep : Step: [flowWriteStep] executed in 3ms
2023-01-04 00:05:49.830 INFO 7829 --- [ main] o.s.b.c.l.support.SimpleJobLauncher : Job: [FlowJob: [name=flowStepJob]] completed with the following parameters: [{}] and the following status: [COMPLETED] in 40ms
2023-01-04 00:05:49.833 INFO 7829 --- [ main] o.s.b.c.l.support.SimpleJobLauncher : Job: [SimpleJob: [name=multipleStepJob]] launched with the following parameters: [{}]
2023-01-04 00:05:49.837 INFO 7829 --- [ main] o.s.batch.core.job.SimpleStepHandler : Executing step: [startStep]
2023-01-04 00:05:49.839 INFO 7829 --- [ main] c.l.batch.config.MultipleStepJobConfig : Start Step<--------
2023-01-04 00:05:49.841 INFO 7829 --- [ main] o.s.batch.core.step.AbstractStep : Step: [startStep] executed in 4ms
2023-01-04 00:05:49.844 INFO 7829 --- [ main] o.s.batch.core.job.SimpleStepHandler : Executing step: [nextStep]
2023-01-04 00:05:49.846 INFO 7829 --- [ main] c.l.batch.config.MultipleStepJobConfig : Next Step<--------
2023-01-04 00:05:49.847 INFO 7829 --- [ main] o.s.batch.core.step.AbstractStep : Step: [nextStep] executed in 3ms
2023-01-04 00:05:49.850 INFO 7829 --- [ main] o.s.batch.core.job.SimpleStepHandler : Executing step: [lastStep]
2023-01-04 00:05:49.852 INFO 7829 --- [ main] c.l.batch.config.MultipleStepJobConfig : Last Step<--------
2023-01-04 00:05:49.853 INFO 7829 --- [ main] o.s.batch.core.step.AbstractStep : Step: [lastStep] executed in 3ms
2023-01-04 00:05:49.855 INFO 7829 --- [ main] o.s.b.c.l.support.SimpleJobLauncher : Job: [SimpleJob: [name=multipleStepJob]] completed with the following parameters: [{}] and the following status: [COMPLETED] in 21ms
2023-01-04 00:05:49.858 INFO 7829 --- [ main] o.s.b.c.l.support.SimpleJobLauncher : Job: [SimpleJob: [name=singleStepJob]] launched with the following parameters: [{}]
2023-01-04 00:05:49.861 INFO 7829 --- [ main] o.s.batch.core.job.SimpleStepHandler : Executing step: [simpleStep]
2023-01-04 00:05:49.862 INFO 7829 --- [ main] c.linetest.batch.tasklet.SimpleTasklet : Execute SimpleTasklet >>>>
2023-01-04 00:05:49.864 INFO 7829 --- [ main] o.s.batch.core.step.AbstractStep : Step: [simpleStep] executed in 3ms
2023-01-04 00:05:49.865 INFO 7829 --- [ main] o.s.b.c.l.support.SimpleJobLauncher : Job: [SimpleJob: [name=singleStepJob]] completed with the following parameters: [{}] and the following status: [COMPLETED] in 7ms
2023-01-04 00:05:49.869 INFO 7829 --- [ionShutdownHook] com.zaxxer.hikari.HikariDataSource : HikariPool-1 - Shutdown initiated...
2023-01-04 00:05:49.871 INFO 7829 --- [ionShutdownHook] com.zaxxer.hikari.HikariDataSource : HikariPool-1 - Shutdown completed.
Upvotes: 2
Views: 7931
Reputation: 978
The issue very clear from logs.
Caused by: java.lang.IllegalArgumentException: Job name must be specified in case of multiple jobs
at org.springframework.boot.autoconfigure.batch.JobLauncherApplicationRunner.validate(JobLauncherApplicationRunner.java:116) ~[spring-boot-autoconfigure-3.0.1.jar:3.0.1]
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:na]
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77) ~[na:na]
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:na]
at java.base/java.lang.reflect.Method.invoke(Method.java:568) ~[na:na]
at org.springframework.beans.factory.annotation.InitDestroyAnnotationBeanPostProcessor$LifecycleElement.invoke(InitDestroyAnnotationBeanPostProcessor.java:424) ~[spring-beans-6.0.3.jar:6.0.3]
at org.springframework.beans.factory.annotation.InitDestroyAnnotationBeanPostProcessor$LifecycleMetadata.invokeInitMethods(InitDestroyAnnotationBeanPostProcessor.java:368) ~[spring-beans-6.0.3.jar:6.0.3]
at org.springframework.beans.factory.annotation.InitDestroyAnnotationBeanPostProcessor.postProcessBeforeInitialization(InitDestroyAnnotationBeanPostProcessor.java:192) ~[spring-beans-6.0.3.jar:6.0.3]
... 17 common frames omitted
If only one job is present in Spring Context then Spring run that job by default on startup but If multiple jobs are present in Spring Context then we need to tell Spring which job to run on startup.
So you can specify this property in application.properties
file and try again.
spring.batch.job.name=singleStepJob
or
spring.batch.job.name=multipleStepJob
or you can disable running job on startup by this property and run the job programmatically using JobLauncher
.
spring.batch.job.enabled=false
How to run job programmatically?
public class JobLauncherService {
private final JobLauncher jobLauncher;
private final Job job;
@Autowired
public JobLauncherService(JobLauncher jobLauncher, @Qualifier("multipleStepJob") Job job) {
this.jobLauncher = jobLauncher;
this.job = job;
}
public void runJob() {
try {
final JobExecution jobExecution = jobLauncher.run(job, new JobParameters());
System.out.println("Job Status : " + jobExecution.getStatus());
System.out.println("Job completed");
} catch (Exception e) {
e.printStackTrace();
System.out.println("Job failed");
}
}
}
Upvotes: 9