how to select which spring batch job to run based on application argument - spring boot java config

27,358

Solution 1

To run the jobs you like from the main method you can load the the required job configuration bean and the JobLauncher from the application context and then run it:

@ComponentScan
@EnableAutoConfiguration
public class ApplicationWithJobLauncher {

    public static void main(String[] args) throws BeansException, JobExecutionAlreadyRunningException, JobRestartException, JobInstanceAlreadyCompleteException, JobParametersInvalidException, InterruptedException {

        Log log = LogFactory.getLog(ApplicationWithJobLauncher.class);

        SpringApplication app = new SpringApplication(ApplicationWithJobLauncher.class);
        app.setWebEnvironment(false);
        ConfigurableApplicationContext ctx= app.run(args);
        JobLauncher jobLauncher = ctx.getBean(JobLauncher.class);
        JobParameters jobParameters = new JobParametersBuilder()
            .addDate("date", new Date())
            .toJobParameters();  

        if("1".equals(args[0])){
            //addNewPodcastJob
            Job addNewPodcastJob = ctx.getBean("addNewPodcastJob", Job.class);          
            JobExecution jobExecution = jobLauncher.run(addNewPodcastJob, jobParameters);                   
        } else {
            jobLauncher.run(ctx.getBean("newEpisodesNotificationJob",  Job.class), jobParameters);   

        } 

        System.exit(0);
    }
}

What was causing my lots of confusion was that the second job were executed, even though the first job seemed to be "picked up" by the runner... Well the problem was that in both job's configuration file I used standard method names writer(), reader(), processor() and step() and it used the ones from the second job that seemed to "overwrite" the ones from the first job without any warnings... I used though an application config class with @EnableBatchProcessing(modular=true), that I thought would be used magically by Spring Boot :

@Configuration
@EnableBatchProcessing(modular=true)
public class AppConfig {

    @Bean
    public ApplicationContextFactory addNewPodcastJobs(){
        return new GenericApplicationContextFactory(AddPodcastJobConfiguration.class);
    }

    @Bean
    public ApplicationContextFactory newEpisodesNotificationJobs(){
        return new GenericApplicationContextFactory(NotifySubscribersJobConfiguration.class);
    }    

}

I will write a blog post about it when it is ready, but until then the code is available at https://github.com/podcastpedia/podcastpedia-batch (work/learning in progress)..

Solution 2

Just set the "spring.batch.job.names=myJob" property. You could set it as SystemProperty when you launch your application (-Dspring.batch.job.names=myjob). If you have defined this property, spring-batch-starter will only launch the jobs, that are defined by this property.

Share:
27,358
amacoder
Author by

amacoder

Updated on May 07, 2020

Comments

  • amacoder
    amacoder about 4 years

    I have two independent spring batch jobs in the same project because I want to use the same infrastructure-related beans. Everything is configured in Java. I would like to know if there's a proper way to start the jobs independent based for example on the first java app argument in the main method for example. If I run SpringApplication.run only the second job gets executed by magic. The main method looks like:

    @ComponentScan
    @EnableAutoConfiguration
    public class Application {
    
        public static void main(String[] args) {                
            SpringApplication app = new SpringApplication(Application.class);
            app.setWebEnvironment(false);
            ApplicationContext ctx= app.run(args);              
        }
    
    }
    

    and the two jobs are configured as presented in the Spring Batch Getting Started tutorial on Spring.io. Here is the configuration file of the first job, the second being configured in the same way.

    @Configuration
    @EnableBatchProcessing
    @Import({StandaloneInfrastructureConfiguration.class, ServicesConfiguration.class})
    public class AddPodcastJobConfiguration {
    
        @Autowired
        private JobBuilderFactory jobs;
    
        @Autowired
        private StepBuilderFactory stepBuilderFactory;
        //reader, writer, processor...
    
    }
    

    To enable modularization I created an AppConfig class, where I define factories for the two jobs:

    @Configuration
    @EnableBatchProcessing(modular=true)
    public class AppConfig {
    
        @Bean
        public ApplicationContextFactory addNewPodcastJobs(){
            return new GenericApplicationContextFactory(AddPodcastJobConfiguration.class);
        }
    
        @Bean
        public ApplicationContextFactory newEpisodesNotificationJobs(){
            return new GenericApplicationContextFactory(NotifySubscribersJobConfiguration.class);
        }    
    
    }
    

    P.S. I am new to Spring configuration in Java configuration Spring Boot and Spring Batch...

  • amacoder
    amacoder almost 10 years
    Thanks Luca, but I didn't have any success with the CommandLineJobRunner either...
  • amacoder
    amacoder over 9 years
  • Pino
    Pino almost 6 years
    This is the right answer when using Spring-batch with Spring-boot. Of course it assumes that BatchAutoConfiguration has not been disabled (it creates a JobLauncherCommandLineRunner and passes the job names to it).