How to use Intercepting Job Execution in Spring Batch

For Intercepting Job Execution feature, Spring Batch provides an interface called JobExecutionListener to notify events in a Job lifecycle. So in the tutorial, JavaSampleApproach will guide how to configure Intercepting Job Execution with JobExecutionListener.

Related Posts:
1. How to start with Spring Batch using Spring Boot – Java Config
2. Spring Batch XML Config by Spring Boot
3. How to use Spring Batch Inheritance function

I. Technologies

– Java 1.8
– Maven 3.3.9
– Spring Tool Suite – Version 3.8.1.RELEASE
– Spring Boot: 1.5.1.RELEASE
– MySQL Database 1.4

II. Intercepting Job Execution

For Intercepting Job Execution, Spring Batch provides an interface JobExecutionListener:

public interface JobExecutionListener {

    void beforeJob(JobExecution jobExecution);
    void afterJob(JobExecution jobExecution);

}

Function void beforeJob(JobExecution jobExecution): is invoked before a job executes.
Function void afterJob(JobExecution jobExecution): is invoked after completion of a job.

For register a job execution listener with Java config, use:
org.springframework.batch.core.job.builder.JobBuilderHelper.listener(JobExecutionListener listener)


@Bean
public Job job() {
    return jobBuilderFactory.get("job")
            .incrementer(new RunIdIncrementer())
            .flow(step1())
            .end()
            // configure Intercepting-Job here
            .listener(interceptingJob)
            .build();
}

For XML register a job execution listener, use: listeners

<job id="job">
    <step id="step1">
        <tasklet>
            <chunk reader="itemReader" processor="itemProcessor" writer="itemWriter" commit-interval="1" />
        </tasklet>
    </step>
    
    <listeners>
    	<listener ref="interceptingJobExecution"/>
	</listeners>
</job>

III. Practice

Step to do:
– Create Spring Boot project
– Create a Job Step
– Create a JobExecutionListener
– Configure Batch Job
– Create a Launch Controller
– Run & Check result

1. Create Spring Boot project

Create a Spring Boot project with needed dependencies:
spring-boot-starter-batch
spring-boot-starter-web
mysql-connector-java

<dependency>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-batch</artifactId>
</dependency>
<dependency>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-web</artifactId>
</dependency>

<dependency>
	<groupId>mysql</groupId>
	<artifactId>mysql-connector-java</artifactId>
	<scope>runtime</scope>
</dependency>

2. Create Job Step

Create a simple Job step with Reader, Writer and Processor:
Reader.java:


package com.javasampleapproach.intercepting.step;
 
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.batch.item.ItemReader;
import org.springframework.batch.item.NonTransientResourceException;
import org.springframework.batch.item.ParseException;
import org.springframework.batch.item.UnexpectedInputException;
 
 
public class Reader implements ItemReader{
 
    private String[] messages = {"Hello World!", "Welcome to Spring Batch!"};
     
    private int count=0;
     
    Logger logger = LoggerFactory.getLogger(this.getClass());
     
    @Override
    public String read() throws Exception, UnexpectedInputException, ParseException, NonTransientResourceException {
         
        if(count < messages.length){
            return messages[count++];
        }else{
            count=0;
        }
        return null;
    }
     
}

- Writer.java:


package com.javasampleapproach.intercepting.step;
 
import java.util.List;
 
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.batch.item.ItemWriter;
 
public class Writer implements ItemWriter {
 
    Logger logger = LoggerFactory.getLogger(this.getClass());
     
    @Override
    public void write(List messages) throws Exception {
        for(String msg : messages){
            System.out.println("#Writer Step: " + msg);
        }
    }
     
}

- Processor.java:


package com.javasampleapproach.intercepting.step;
 
import org.springframework.batch.item.ItemProcessor;
 
public class Processor implements ItemProcessor{
 
    @Override
    public String process(String content) throws Exception {
        return content.toUpperCase();
    }
 
}

3. Create a JobExecutionListener

Create a Intercepting Job Execution by implementing interface: JobExecutionListener


package com.javasampleapproach.intercepting.listener;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.batch.core.JobExecution;
import org.springframework.batch.core.JobExecutionListener;
import org.springframework.stereotype.Component;

@Component
public class InterceptingJobExecution implements JobExecutionListener{
	
	private Logger log = LoggerFactory.getLogger(this.getClass());

	@Override
	public void beforeJob(JobExecution jobExecution) {
		//
		// Can Log || do some business code
		//
		log.info("Intercepting Job Excution - Before Job!");
	}

	@Override
	public void afterJob(JobExecution jobExecution) {
		//
		// Can Log || do some Business code
		//
		log.info("Intercepting Job Excution - After Job!");
	}

}

4. Config Batch Job

- Java Config, use:org.springframework.batch.core.job.builder.JobBuilderHelper.listener(JobExecutionListener listener)


package com.javasampleapproach.intercepting.config;
 
import org.springframework.batch.core.Job;
import org.springframework.batch.core.Step;
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.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import com.javasampleapproach.intercepting.listener.InterceptingJobExecution;
import com.javasampleapproach.intercepting.step.Processor;
import com.javasampleapproach.intercepting.step.Reader;
import com.javasampleapproach.intercepting.step.Writer;

 
@Configuration
public class BatchConfig {
 
    @Autowired
    public JobBuilderFactory jobBuilderFactory;
 
    @Autowired
    public StepBuilderFactory stepBuilderFactory;
 
    @Autowired
    InterceptingJobExecution interceptingJob;
    
     
    @Bean
    public Job job() {
        return jobBuilderFactory.get("job")
                .incrementer(new RunIdIncrementer())
                .flow(step1())
                .end()
                // configure Intercepting-Job here
                .listener(interceptingJob)
                .build();
    }
 
    @Bean
    public Step step1() {
        return stepBuilderFactory.get("step1")
                . chunk(1)
                .reader(new Reader())
                .processor(new Processor())
                .writer(new Writer())
                .build();
    }

}

- XML config, use: listeners

<beans:beans xmlns="http://www.springframework.org/schema/batch"
	xmlns:beans="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="
           http://www.springframework.org/schema/beans
           http://www.springframework.org/schema/beans/spring-beans.xsd
           http://www.springframework.org/schema/batch
           http://www.springframework.org/schema/batch/spring-batch-3.0.xsd">

	<job id="job">
		<step id="step1">
			<tasklet>
				<chunk reader="itemReader" processor="itemProcessor" writer="itemWriter"
					commit-interval="1" />
			</tasklet>
		</step>

		<listeners>
			<listener ref="interceptingJobExecution" />
		</listeners>
	</job>

	<beans:bean id="itemReader"
		class="com.javasampleapproach.intercepting.step.Reader" />
	<beans:bean id="itemProcessor"
		class="com.javasampleapproach.intercepting.step.Processor" />
	<beans:bean id="itemWriter"
		class="com.javasampleapproach.intercepting.step.Writer" />

	<!-- Listener -->
	<beans:bean id="interceptingJobExecution"
		class="com.javasampleapproach.intercepting.listener.InterceptingJobExecution" />

</beans:beans>

- Open application.properties file to configure database for batch job:


spring.datasource.url=jdbc:mysql://localhost:3306/testdb
spring.datasource.username=root
spring.datasource.password=12345
spring.batch.job.enabled=false

- Enable Batch Job config:


package com.javasampleapproach.intercepting;

import org.springframework.batch.core.configuration.annotation.EnableBatchProcessing;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@EnableBatchProcessing
@SpringBootApplication
public class SpringBatchJobExecutionApplication {

	public static void main(String[] args) {
		SpringApplication.run(SpringBatchJobExecutionApplication.class, args);
	}
}

With XML config, need import batchjob.xml file: @ImportResource("classpath:batchjob.xml")

5. Create a Launch Controller

Create a simple controller for launching job:


package com.javasampleapproach.intercepting.controller;
 
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.batch.core.Job;
import org.springframework.batch.core.JobParameters;
import org.springframework.batch.core.JobParametersBuilder;
import org.springframework.batch.core.launch.JobLauncher;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
 
@RestController
public class JobLauncherController {
 
    @Autowired
    JobLauncher jobLauncher;
 
    @Autowired
    Job job;
    
    @RequestMapping("/launchjob")
    public String handle() throws Exception {
 
        Logger logger = LoggerFactory.getLogger(this.getClass());
        try {
            JobParameters jobParameters = new JobParametersBuilder().addLong("time", System.currentTimeMillis())
                    .toJobParameters();
            jobLauncher.run(job, jobParameters);
        } catch (Exception e) {
            logger.info(e.getMessage());
        }
 
        return "Done";
    }
}

6. Run & Check result

- Build & Run the project with Spring Boot mode.
- Launch the Job by a request: http://localhost:8080/launchjob


o.s.b.c.l.support.SimpleJobLauncher      : Job: [FlowJob: [name=job]] launched with the following parameters: [{time=1487930196844}]
c.j.i.listener.InterceptingJobExecution  : Intercepting Job Excution - Before Job!
o.s.batch.core.job.SimpleStepHandler     : Executing step: [step1]
#Writer Step: HELLO WORLD!
#Writer Step: WELCOME TO SPRING BATCH!
c.j.i.listener.InterceptingJobExecution  : Intercepting Job Excution - After Job!
o.s.b.c.l.support.SimpleJobLauncher      : Job: [FlowJob: [name=job]] completed with the following parameters: [{time=1487930196844}] and the following status: [COMPLETED]

IV. Sourcecode

1. SpringBatchInterceptingJobExecution
2. SpringBatchInterceptingJobExecutionXMLConfig

3 thoughts on “How to use Intercepting Job Execution in Spring Batch”

  1. Have you ever considered about including a little bit more than just your articles?
    I mean, what you say is valuable and all.
    But imagine if you added some great pictures or video
    clips to give your posts more, “pop”! Your content is excellent but with images and videos, this site could definitely be one of
    the most beneficial in its field. Terrific blog!

  2. I would like to convey my gratitude for your kind-heartedness in support of all those that should have guidance on this particular subject matter. Your personal commitment to passing the message along appeared to be definitely productive and has frequently enabled professionals much like me to arrive at their pursuits. Your entire insightful useful information can mean this much a person like me and especially to my office workers. With thanks; from each one of us.

Leave a Reply

Your email address will not be published. Required fields are marked *