15

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
  • 791
  • 2
  • 7
  • 11
  • This is not a Spring Boot application. If you have something that works with Spring Boot, why do you need help? – Dave Syer Aug 06 '14 at 05:17
  • 1
    Sorry Dave for my stupid question but I am new to Spring Boot, Spring Batch and Java configuration. What I would like to achieve is have the two+ jobs in the same code base, so that they can share the JPA entities for example..., but still be able to run them separately somehow with Spring Boot. – amacoder Aug 06 '14 at 16:50

4 Answers4

26

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.

Hansjoerg Wingeier
  • 4,274
  • 4
  • 17
  • 25
  • 1
    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). – Pino Jun 07 '18 at 10:25
  • There is a typo in answer above. It should be `-Dspring.batch.job.name=myjob`. The example command would be `java -jar -Dspring.batch.job.name=myjob yourjarname.jar` – Sxc-Dev Feb 13 '23 at 21:48
12

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)..

amacoder
  • 791
  • 2
  • 7
  • 11
  • 1
    As promised, blog post is there [Spring Batch Tutorial with Spring Boot and Java Configuration](http://www.codingpedia.org/ama/spring-batch-tutorial-with-spring-boot-and-java-configuration/) – amacoder Sep 10 '14 at 13:27
0

There is the CommandLineJobRunner and maybe can be helpful.
From its javadoc

Basic launcher for starting jobs from the command line

Luca Basso Ricci
  • 17,829
  • 2
  • 47
  • 69
0

Spring Batch auto configuration is enabled by adding @EnableBatchProcessing (from Spring Batch) somewhere in your context. By default it executes all Jobs in the application context on startup (see JobLauncherCommandLineRunner for details). You can narrow down to a specific job or jobs by specifying spring.batch.job.names (comma separated job name patterns).

-- Spring Boot Doc

Or disable the auto execution and run the jobs programmatically from the context using a JobLauncher based on the args passed to the main method