Search code examples
springspring-batchjobs

How to launch a Job


I'm currently trying to launch a Job programatically in my Spring application.

Here is my actual code:

public void launchJob(String[] args)
            throws JobParametersInvalidException, JobExecutionAlreadyRunningException, JobRestartException,
            JobInstanceAlreadyCompleteException {
        
    String jobName = args[0];

    JobLauncher jobLauncher = context.getBean(JobLauncher.class);
    Job job = context.getBean(jobName, Job.class);
    JobParameters jobParameters = getJobParameters(args);


    JobExecution jobExecution = jobLauncher.run(job, jobParameters);
    BatchStatus batchStatus = jobExecution.getStatus();
}

And how I launch it :

String[] args = {"transformXML2CSV", "myFile.xml", "myFile.csv"};
springBatchJobRunner.launchJob(args);

But I have some troubles during the launch, the first is to retrieve the app context, my first try was to annotate my class with a @Service and use an @Autowired like this:

@Autowired
private ApplicationContext context;

But with this way my context is always null.

My second try was to get the context by this way:

ApplicationContext context = new AnnotationConfigApplicationContext(SpringBatchNoDatabaseConfiguration.class);

The SpringBatchNoDatabaseConfiguration is my @Configuration and the Job is inside it.

Using this my context is not null but I have a strange behavior and I can't understand why and how to prevent this:

I run the launchJob function from my processor class, then when I get the context by AnnotationConfigApplicationContext my processor class is rebuild and I have a NullPointerException in it stopping all the process.

I really don't understand the last part, why it's relaunching my processor class when I get the context ?


Solution

  • As indicated in comments above, you run a parent batch (with spring-batch) which at a moment needs your job to process an xml file.

    I suggest you keep the same spring-batch context and run the process xml file job as a nested job of the parent job. You can do that using JobStep class and spring batch controlling step flow feature. As an example, here is what your parent job would like to :

    public Job parentJob(){
       JobParameters processXmlFileJobParameters = getJobParameters(String[]{"transformXML2CSV", "myFile.xml", "myFile.csv"});
       return this.jobBuilderFactory.get("parentJob")
                .start(firstStepOfParentJob())
                .on("PROCESS_XML_FILE").to(processXmlFileStep(processXmlFileJobParameters)
                .from(firstStepOfParentJob()).on("*").to(lastStepOfParentJob())
                .from(processXmlFileStep(processXmlFileJobParameters))
                .next(lastStepOfParentJob())
                .end().build();
    }
    
    public Step firstStepOfParentJob(){
       return stepBuilderFactory.get("firstStepOfParentJob")
              // ... depends on your parent job's business
              .build();
    }
    
    public Step lastStepOfParentJob(){
        return stepBuilderFactory.get("lastStepOfParentJob")
              // ... depends on your parent job's business
              .build();
    } 
    
    public Step processXmlFileStep(JobParameters processXmlFileJobParameters){
        return stepBuilderFactory.get("processXmlFileStep")
                                 .job(processXmlFileJob())
                                 .parametersExtractor((job,exec)->processXmlFileJobParameters)
                                 .build();
    }
    
    public Job processXmlFileJob(){
        return jobBuilderFactory.get("processXmlFileJob")
              // ... describe here your xml process job
              .build();
    }