We have seen how to schedule a task using spring boot and how to run a batch job using spring boot in below posts.
In this example, We will see how to run that Batch job with spring scheduler using spring boot.
Step 1 : By default, the batch job runs immediately when we start the application. So we have to disable the auto run feature in application.properties file.
spring.batch.job.enabled=false
Step 2 : Configure JobLauncher in one more configuration class with defining required dependant components.
package com.kswaughs.config; import org.springframework.batch.core.launch.support.SimpleJobLauncher; import org.springframework.batch.core.repository.JobRepository; import org.springframework.batch.core.repository.support.MapJobRepositoryFactoryBean; import org.springframework.batch.support.transaction.ResourcelessTransactionManager; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.scheduling.annotation.EnableScheduling; @Configuration @EnableScheduling public class BatchScheduler { @Bean public ResourcelessTransactionManager transactionManager() { return new ResourcelessTransactionManager(); } @Bean public MapJobRepositoryFactoryBean mapJobRepositoryFactory( ResourcelessTransactionManager txManager) throws Exception { MapJobRepositoryFactoryBean factory = new MapJobRepositoryFactoryBean(txManager); factory.afterPropertiesSet(); return factory; } @Bean public JobRepository jobRepository( MapJobRepositoryFactoryBean factory) throws Exception { return factory.getObject(); } @Bean public SimpleJobLauncher jobLauncher(JobRepository jobRepository) { SimpleJobLauncher launcher = new SimpleJobLauncher(); launcher.setJobRepository(jobRepository); return launcher; } }
Step 3 : Follow the below methods
Import the above Configuration class to your batch configuration class.
Get the reference of the configured JobLauncher through autowired injection.
Write a new method annotated with @Scheduled and desired cron expression.
Run the JobLauncher with passing job bean and custom job parameter.
package com.kswaughs.config; import java.util.Date; import org.springframework.batch.core.Job; import org.springframework.batch.core.JobExecution; import org.springframework.batch.core.JobExecutionListener; import org.springframework.batch.core.JobParameters; import org.springframework.batch.core.JobParametersBuilder; import org.springframework.batch.core.Step; import org.springframework.batch.core.configuration.annotation.EnableBatchProcessing; import org.springframework.batch.core.configuration.annotation.JobBuilderFactory; import org.springframework.batch.core.configuration.annotation.StepBuilderFactory; import org.springframework.batch.core.launch.support.RunIdIncrementer; import org.springframework.batch.core.launch.support.SimpleJobLauncher; import org.springframework.batch.item.ItemWriter; import org.springframework.batch.item.file.FlatFileItemReader; import org.springframework.batch.item.file.mapping.BeanWrapperFieldSetMapper; import org.springframework.batch.item.file.mapping.DefaultLineMapper; import org.springframework.batch.item.file.transform.DelimitedLineTokenizer; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Import; import org.springframework.core.io.ClassPathResource; import org.springframework.scheduling.annotation.Scheduled; import com.kswaughs.beans.Order; import com.kswaughs.beans.SvcReq; import com.kswaughs.order.OrderSvcInvoker; import com.kswaughs.processor.JobCompletionNotificationListener; import com.kswaughs.processor.OrderItemProcessor; @Configuration @EnableBatchProcessing @Import({BatchScheduler.class}) public class BatchConfiguration { @Autowired private SimpleJobLauncher jobLauncher; @Autowired public JobBuilderFactory jobBuilderFactory; @Autowired public StepBuilderFactory stepBuilderFactory; @Scheduled(cron = "1 53/3 17 * * ?") public void perform() throws Exception { System.out.println("Job Started at :" + new Date()); JobParameters param = new JobParametersBuilder().addString("JobID", String.valueOf(System.currentTimeMillis())).toJobParameters(); JobExecution execution = jobLauncher.run(processOrderJob(), param); System.out.println("Job finished with status :" + execution.getStatus()); } @Bean public Job processOrderJob() { return jobBuilderFactory.get("processOrderJob") .incrementer(new RunIdIncrementer()) .listener(listener()) .flow(orderStep()).end().build(); } @Bean public Step orderStep() { return stepBuilderFactory.get("orderStep").<Order, SvcReq> chunk(3) .reader(reader()).processor(processor()).writer(writer()) .build(); } @Bean public FlatFileItemReader<Order> reader() { FlatFileItemReader<Order> reader = new FlatFileItemReader<Order>(); reader.setResource(new ClassPathResource("PhoneData.csv")); reader.setLineMapper(new DefaultLineMapper<Order>() { { setLineTokenizer(new DelimitedLineTokenizer() { { setNames(new String[] { "orderID", "orderName" }); } }); setFieldSetMapper(new BeanWrapperFieldSetMapper<Order>() { { setTargetType(Order.class); } }); } }); return reader; } @Bean public OrderItemProcessor processor() { return new OrderItemProcessor(); } @Bean public ItemWriter<SvcReq> writer() { return new OrderSvcInvoker(); } @Bean public JobExecutionListener listener() { return new JobCompletionNotificationListener(); } }
In this example, I configured the job to start at '5 PM 53 minutes 1 second' and run for every 3 minutes till 6 PM with cron expression.
Output console logs
Job Started at :Tue Mar 22 17:53:01 IST 2016 2016-03-22 17:53:01.052 INFO 10932 --- [pool-2-thread-1] o.s.b.c.l.support.SimpleJobLauncher: Job: [FlowJob: [name=processOrderJob]] launched with the following parameters: [{JobID=1458649381004}] 2016-03-22 17:53:01.078 INFO 10932 --- [pool-2-thread-1] o.s.batch.core.job.SimpleStepHandler: Executing step: [orderStep] Converting (Order [orderID=101, orderName=Apple IPhone]) into (SvcReq [id=101, name=APPLE IPHONE]) Converting (Order [orderID=102, orderName=Samsung Galaxy Y]) into (SvcReq [id=102, name=SAMSUNG GALAXY Y]) Converting (Order [orderID=103, orderName=Moto E]) into (SvcReq [id=103, name=MOTO E]) calling web service:SvcResp [id=101, message=APPLE IPHONE Processed successfully] calling web service:SvcResp [id=102, message=SAMSUNG GALAXY Y Processed successfully] calling web service:SvcResp [id=103, message=MOTO E Processed successfully] Processed items:3 Converting (Order [orderID=104, orderName=Moto X]) into (SvcReq [id=104, name=MOTO X]) Converting (Order [orderID=105, orderName=Yuphoria]) into (SvcReq [id=105, name=YUPHORIA]) calling web service:SvcResp [id=104, message=MOTO X Processed successfully] calling web service:SvcResp [id=105, message=YUPHORIA Processed successfully] Processed items:2 BATCH JOB FINISHED SUCCESSFULLY 2016-03-22 17:53:01.350 INFO 10932 --- [pool-2-thread-1] o.s.b.c.l.support.SimpleJobLauncher: Job: [FlowJob: [name=processOrderJob]] completed with the following parameters: [{JobID=1458649381004}] and the following status: [COMPLETED] Job finished with status :COMPLETED Job Started at :Tue Mar 22 17:56:00 IST 2016 2016-03-22 17:56:01.006 INFO 10932 --- [pool-2-thread-1] o.s.b.c.l.support.SimpleJobLauncher: Job: [FlowJob: [name=processOrderJob]] launched with the following parameters: [{JobID=1458649560996}] 2016-03-22 17:56:01.031 INFO 10932 --- [pool-2-thread-1] o.s.batch.core.job.SimpleStepHandler: Executing step: [orderStep] Converting (Order [orderID=101, orderName=Apple IPhone]) into (SvcReq [id=101, name=APPLE IPHONE]) Converting (Order [orderID=102, orderName=Samsung Galaxy Y]) into (SvcReq [id=102, name=SAMSUNG GALAXY Y]) Converting (Order [orderID=103, orderName=Moto E]) into (SvcReq [id=103, name=MOTO E]) calling web service:SvcResp [id=101, message=APPLE IPHONE Processed successfully] calling web service:SvcResp [id=102, message=SAMSUNG GALAXY Y Processed successfully] calling web service:SvcResp [id=103, message=MOTO E Processed successfully] Processed items:3 Converting (Order [orderID=104, orderName=Moto X]) into (SvcReq [id=104, name=MOTO X]) Converting (Order [orderID=105, orderName=Yuphoria]) into (SvcReq [id=105, name=YUPHORIA]) calling web service:SvcResp [id=104, message=MOTO X Processed successfully] calling web service:SvcResp [id=105, message=YUPHORIA Processed successfully] Processed items:2 BATCH JOB FINISHED SUCCESSFULLY 2016-03-22 17:56:01.154 INFO 10932 --- [pool-2-thread-1] o.s.b.c.l.support.SimpleJobLauncher: Job: [FlowJob: [name=processOrderJob]] completed with the following parameters: [{JobID=1458649560996}] and the following status: [COMPLETED] Job finished with status :COMPLETED
Nice share.
ReplyDeleteWould you please make this project as github repo?
I think it would be help others.
Thanks
Thanks for the great share! it's working but I found an issue as those BATCH_* tables did not get updated. So, I just use the @EnableScheduling annotation in my current job configuration and I refer the the auto-initiated launcher instead:
ReplyDelete@Autowired
private JobLauncher jobLauncher;
This works with the same results while maintaining the BATCH_* records created.
Can you explain me further on this step... even I facing the save issues
DeleteI have this error when i execute the project
ReplyDeleteCaused by: org.springframework.beans.factory.BeanCreationException: Could not autowire field: private org.springframework.batch.core.launch.support.SimpleJobLauncher fr.cc.suivireco.salesmanagement.batch.impl.organismeImport.BatchConfiguratioOrganisme.jobLauncher; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [org.springframework.batch.core.launch.support.SimpleJobLauncher] found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)}
any idea?
Please check the package name you added in @ComponentScan({ "com.kswaughs" }) of your main class.
DeleteIn my case, all my packages are under "com.kswaughs".
Please check the package name you added in @ComponentScan({ "com.kswaughs" }) of your main class.
ReplyDeleteIn my case, all my packages are under "com.kswaughs".
Thanks for the great walkthrough!
ReplyDeleteHi, I am trying to use BatchScheduler in my spring batch project, but getting the below error any help is really appreciated.
ReplyDelete***************************
APPLICATION FAILED TO START
***************************
Description:
Parameter 0 of method mapJobRepositoryFactory in com.barley.batch.BatchScheduler required a bean of type 'org.springframework.batch.support.transaction.ResourcelessTransactionManager' that could not be found.
Action:
Consider defining a bean of type 'org.springframework.batch.support.transaction.ResourcelessTransactionManager' in your configuration.
Hi,Thanks for the post . I followed your approach to schedule a spring batch Job but I have multiple jobs which i have to schedule. I am not able to achieve it. Can you please help me with it ?
ReplyDeleteReader is in an infinity loop. How to stop reader after the chunk?.
ReplyDelete